Overview
The Coral Tracker API lets you programmatically manage your coral inventory. Use it to integrate with e-commerce platforms, build custom dashboards, or sync data with mobile apps.
Base URL
https://api.coral-tracker.com/api/v1
Authentication
All requests must include your API key in the X-API-Key header. API keys start with ctk_.
Keep your key secret. Never expose it in client-side code, public repos, or URLs. If compromised, delete it and create a new one.
# Test your API key
curl -H "X-API-Key: ctk_your_key_here" \
https://api.coral-tracker.com/api/v1/corals
const response = await fetch('https://api.coral-tracker.com/api/v1/corals', {
headers: {
'X-API-Key': 'ctk_your_key_here',
'Accept': 'application/json'
}
});
const data = await response.json();
console.log(data);
<?php
$ch = curl_init('https://api.coral-tracker.com/api/v1/corals');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'X-API-Key: ctk_your_key_here',
'Accept: application/json',
],
]);
$response = curl_exec($ch);
$data = json_decode($response, true);
print_r($data);
import requests
response = requests.get(
'https://api.coral-tracker.com/api/v1/corals',
headers={'X-API-Key': 'ctk_your_key_here'}
)
data = response.json()
print(data)
Rate Limiting
Requests are rate-limited per organization. Check the response headers to monitor your usage:
| Header | Description |
|---|---|
X-RateLimit-Limit | Max requests per minute |
X-RateLimit-Remaining | Requests left in current window |
X-RateLimit-Reset | Unix timestamp when the window resets |
Retry-After | Seconds to wait (only on 429 responses) |
Plans & Access
Free
$0
- 1 API key (read-only)
- 60 req/min
- 10 corals
Premium
€4.99/mo
- 5 API keys (read + write)
- 120 req/min
- Unlimited corals
Enterprise
€14.99/mo
- Unlimited keys (full access)
- 300 req/min
- Webhooks
/corals
Retrieve a paginated list of corals for your organization.
Query Parameters
| Param | Type | Default | Description |
|---|---|---|---|
per_page | integer | 20 | Items per page (max 100) |
page | integer | 1 | Page number |
for_sale | string | — | Set to true to only get corals marked for sale |
type | string | — | Filter by type: SPS, LPS, Soft, NPS, Anemone, Zoa, Other |
search | string | — | Search by name or species |
curl -H "X-API-Key: ctk_your_key" \
"https://api.coral-tracker.com/api/v1/corals?for_sale=true&per_page=10"
const res = await fetch('https://api.coral-tracker.com/api/v1/corals?for_sale=true&per_page=10', {
headers: { 'X-API-Key': 'ctk_your_key' }
});
const { data, meta } = await res.json();
console.log(`Page ${meta.current_page} of ${meta.last_page}`);
$response = file_get_contents(
'https://api.coral-tracker.com/api/v1/corals?for_sale=true',
false,
stream_context_create(['http' => [
'header' => "X-API-Key: ctk_your_key\r\nAccept: application/json"
]])
);
$data = json_decode($response, true);
response = requests.get(
'https://api.coral-tracker.com/api/v1/corals',
headers={'X-API-Key': 'ctk_your_key'},
params={'for_sale': 'true', 'per_page': 10}
)
corals = response.json()['data']
Example Response
{
"data": [
{
"id": 1,
"name": "Blue Acropora",
"species": "Acropora millepora",
"type": "SPS",
"price_when_added": 49.99,
"current_frag_count": 25,
"health_status": "excellent",
"is_for_sale": true,
"image_url": "https://...",
"gallery_urls": ["https://...", "https://..."],
"images": [
{ "id": 1, "image_url": "https://...", "is_primary": true }
]
}
],
"meta": {
"current_page": 1,
"per_page": 10,
"total": 42,
"last_page": 5
}
}
/corals/{id}
Retrieve a specific coral with its full update history and images.
curl -H "X-API-Key: ctk_your_key" \
https://api.coral-tracker.com/api/v1/corals/1
const res = await fetch('https://api.coral-tracker.com/api/v1/corals/1', {
headers: { 'X-API-Key': 'ctk_your_key' }
});
const coral = (await res.json()).data;
$ch = curl_init('https://api.coral-tracker.com/api/v1/corals/1');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['X-API-Key: ctk_your_key'],
]);
$coral = json_decode(curl_exec($ch), true)['data'];
/corals
write permissionCreate a new coral entry in your inventory.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Coral name (max 255) |
species | string | No | Scientific species name |
purchased_at | date | Yes | Purchase date (YYYY-MM-DD) |
price_when_added | number | Yes | Purchase price |
price_per_frag | number | Yes | Price per frag |
initial_frag_count | integer | Yes | Starting frag count (min: 1) |
current_frag_count | integer | No | Defaults to initial count |
notes | string | No | Any notes |
health_status | string | No | excellent, good, fair, or poor (default: good) |
curl -X POST https://api.coral-tracker.com/api/v1/corals \
-H "X-API-Key: ctk_your_key" \
-H "Content-Type: application/json" \
-d '{
"name": "Blue Acropora",
"species": "Acropora millepora",
"purchased_at": "2026-01-15",
"price_when_added": 49.99,
"price_per_frag": 5.00,
"initial_frag_count": 10,
"health_status": "good"
}'
const res = await fetch('https://api.coral-tracker.com/api/v1/corals', {
method: 'POST',
headers: {
'X-API-Key': 'ctk_your_key',
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'Blue Acropora',
species: 'Acropora millepora',
purchased_at: '2026-01-15',
price_when_added: 49.99,
price_per_frag: 5.00,
initial_frag_count: 10,
health_status: 'good'
})
});
const newCoral = (await res.json()).data;
$ch = curl_init('https://api.coral-tracker.com/api/v1/corals');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'X-API-Key: ctk_your_key',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'name' => 'Blue Acropora',
'species' => 'Acropora millepora',
'purchased_at' => '2026-01-15',
'price_when_added' => 49.99,
'price_per_frag' => 5.00,
'initial_frag_count' => 10,
]),
]);
$result = json_decode(curl_exec($ch), true);
/corals/{id}
write permissionUpdate an existing coral. Only include the fields you want to change.
curl -X PUT https://api.coral-tracker.com/api/v1/corals/1 \
-H "X-API-Key: ctk_your_key" \
-H "Content-Type: application/json" \
-d '{"current_frag_count": 25, "health_status": "excellent"}'
const res = await fetch('https://api.coral-tracker.com/api/v1/corals/1', {
method: 'PUT',
headers: {
'X-API-Key': 'ctk_your_key',
'Content-Type': 'application/json'
},
body: JSON.stringify({
current_frag_count: 25,
health_status: 'excellent'
})
});
$ch = curl_init('https://api.coral-tracker.com/api/v1/corals/1');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'PUT',
CURLOPT_HTTPHEADER => [
'X-API-Key: ctk_your_key',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'current_frag_count' => 25,
'health_status' => 'excellent',
]),
]);
$result = json_decode(curl_exec($ch), true);
/corals/{id}
delete permissionPermanently delete a coral and all associated data.
Warning: This action is irreversible. The coral and all its update history will be permanently deleted.
curl -X DELETE https://api.coral-tracker.com/api/v1/corals/1 \
-H "X-API-Key: ctk_your_key"
await fetch('https://api.coral-tracker.com/api/v1/corals/1', {
method: 'DELETE',
headers: { 'X-API-Key': 'ctk_your_key' }
});
Webhooks
Receive real-time HTTP notifications when events happen in your account. (Enterprise plan)
Available Events
coral.created
coral.updated
coral.deleted
coral.update.created
Signature Verification
Each webhook includes headers for verification:
# Headers sent with each webhook
X-Webhook-Signature: <hmac_sha256>
X-Webhook-Timestamp: <unix_timestamp>
X-Webhook-Event: coral.created
# Verify with:
signature = hmac_sha256(secret, timestamp + '.' + json_body)
Error Handling
All errors follow a consistent JSON format:
{
"error": "Validation failed",
"message": "The provided data is invalid",
"errors": {
"name": ["The name field is required."]
}
}
HTTP Status Codes
| Code | Meaning | When |
|---|---|---|
| 200 | OK | Request successful |
| 201 | Created | New coral created |
| 401 | Unauthorized | Missing or invalid API key |
| 403 | Forbidden | API disabled or coral limit reached |
| 404 | Not Found | Coral doesn't exist |
| 422 | Validation Error | Invalid request data |
| 429 | Rate Limited | Too many requests |
| 500 | Server Error | Something went wrong |