Developer-facing reference for authentication, image recognition, and feedback submission.
The Fishial Recognition API lets you:
The API uses JSON for authentication and feedback requests. Image recognition requests send raw binary image data in the request body.
Base URL
https://api-recognition.fishial.ai
Obtain a short-lived bearer token required for most API requests.
Endpoint
POST /v2/auth
Content-Type
Content-Type: application/json
{
"client_id": "YOUR_CLIENT_ID",
"client_secret": "YOUR_CLIENT_SECRET"
}
| Field | Required | Description |
|---|---|---|
client_id |
✓ | API Key ID provided by Fishial. |
client_secret |
✓ | API Secret Key provided by Fishial. |
{
"token_type": "Bearer",
"access_token": "eyJhbGciOiJIUzI1NiJ9..."
}
401 with error code auth_token_expired./v2/auth calls with the same credentials within a short window may return the same access token. Treat the token as opaque and reusable until its TTL elapses — do not assume each auth call mints a fresh token.POST is supported on /v2/auth; other HTTP methods return 404.curl --request POST \
--url https://api-recognition.fishial.ai/v2/auth \
--header 'Content-Type: application/json' \
--data '{
"client_id": "YOUR_CLIENT_ID",
"client_secret": "YOUR_CLIENT_SECRET"
}'
Scan an image and return detected fish objects with candidate species matches.
Endpoint
POST /v2/recognize
Authorization
Authorization: Bearer YOUR_ACCESS_TOKEN
The server detects the image format from the file's magic bytes, not from the Content-Type header value. Any of the following are accepted for a valid image body:
image/jpeg, image/png, image/webp, image/gif, image/heic, image/heif, image/avif, image/tiff, image/svg+xmlapplication/octet-streamA Content-Type header that does not start with image/ or application/octet-stream (for example text/plain or text/html) will be rejected. A missing Content-Type header returns HTTP 400.
Examples:
Content-Type: image/jpeg
Content-Type: application/octet-stream
Raster
Vector
Not supported
413)422 with error code image_dimensions){
"ok": true,
"queryToken": "QUERY_TOKEN",
"objects": [
{
"shape": [12.4, 40.1, 20.2, 38.6, 28.9, 45.0],
"bbox": [12, 38, 90, 120],
"species": [
{
"id": "SPECIES_UUID",
"certainty": 0.97
}
]
}
],
"definitions": {
"SPECIES_UUID": {
"commonName": "Mahi-mahi",
"scientificName": "Coryphaena hippurus",
"imageUrl": "https://..."
}
}
}
| Field | Type | Description |
|---|---|---|
ok |
boolean | Success indicator. |
queryToken |
string | Token required when sending feedback for this recognition result. |
objects |
array | Detected fish objects, best species match first. |
objects[].shape |
array of numbers | Fish outline polygon as flat coordinate pairs: [x1, y1, x2, y2, ...]. |
objects[].bbox |
array of 4 numbers | Bounding box as [x1, y1, x2, y2]. |
objects[].species |
array | Candidate species matches for the object. |
objects[].species[].id |
string (UUID) | Species UUID; look up in definitions. |
objects[].species[].certainty |
number | Confidence value, 0.0–1.0. Values > 0.80 are high confidence; values < 0.30 are low confidence. |
definitions |
object (map) | Lookup map from species UUID to display metadata. |
definitions[speciesId].commonName |
string | Common English name. |
definitions[speciesId].scientificName |
string | Latin binomial. |
definitions[speciesId].imageUrl |
string (URL) | Reference image URL. |
curl --request POST \
--url https://api-recognition.fishial.ai/v2/recognize \
--header "Authorization: Bearer YOUR_ACCESS_TOKEN" \
--header "Content-Type: image/jpeg" \
--data-binary @fish.jpg
Recognition options are passed as custom HTTP headers on the /v2/recognize request.
| ✓ Use | ✗ Avoid |
|---|---|
| ASCII alphanumeric characters | Diacritics (é, ñ, ö, …) |
| Spaces | CJK characters (Chinese, Japanese, Korean) |
| Basic punctuation | Emoji and other non–Latin-1 characters |
| Line breaks |
Header values containing emoji or non–Latin-1 characters can cause HTTP 500 errors. Sanitize tag and metadata values to ASCII or Latin-1 before sending.
Fishial-Fish-Detection-ThresholdControls fish detection sensitivity.
0.3 ≤ threshold < 1.0 (lower bound inclusive, upper bound exclusive).1.0 exactly is rejected with bad_recognition_option. Negative and non-numeric values are also rejected.0.3 may currently be accepted but produce noisier detections and are not officially supported — stay within the documented range.Example:
Fishial-Fish-Detection-Threshold: 0.5
Fishial-Fish-Shape-Max-PointsControls the maximum number of points in the detected fish polygon.
Example:
Fishial-Fish-Shape-Max-Points: 64
These headers apply only when the image is being uploaded to a Fishial Portal collection. They are not described as general-purpose recognition parameters.
Fishial-Face-ObfuscationBlurs detected human faces. The source docs note that this may partially blur fish if a face is too close.
Example:
Fishial-Face-Obfuscation: true
Fishial-Image-License-CodeAllowed values include:
NoneUnknownCustomCC0-1.0CC-BY-4.0CC-BY-NC-4.0CC-BY-NC-ND-4.0CC-BY-NC-SA-4.0CC-BY-ND-4.0CC-BY-SA-4.0Fishial-Image-License-UrlLicense URL, primarily relevant when using Custom.
Fishial-Image-License-AuthorName of the image author.
Fishial-Image-License-SourceText or URL describing where the image came from.
Fishial-Image-License-NoticeAdditional copyright information.
Fishial-Image-TagsComma-separated list of tags.
Examples:
Fishial-Image-Tags: wow,a,tag
Creates three tags.
Fishial-Image-Tags: wow a tag
Creates one tag.
Fishial-Location-Lat-LonObservation coordinates in decimal degrees.
Example:
Fishial-Location-Lat-Lon: -55.260, -67.886
Send user feedback about a recognition response.
Endpoint
POST /v2/feedback
Authorization
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type
Content-Type: application/json
{
"queryToken": "QUERY_TOKEN",
"objectIndex": 0,
"opinion": "Disagree",
"suggestedSpeciesName": "Yellowfin tuna",
"suggestedSpeciesID": "SPECIES_UUID"
}
| Field | Required | Type | Description |
|---|---|---|---|
queryToken |
✓ | string | Returned by /v2/recognize. |
objectIndex |
✓ | integer or null |
Zero-based object index in the objects array. Set to null to refer to the recognition result as a whole (e.g. when no fish was found). |
opinion |
✓ | string | One of Agree, Disagree, or Unsure. Case-sensitive. |
suggestedSpeciesName |
string | Suggested correction by common or scientific name. | |
suggestedSpeciesID |
string (UUID) | Suggested correction using a species UUID. |
{
"ok": true
}
curl --request POST \
--url https://api-recognition.fishial.ai/v2/feedback \
--header "Authorization: Bearer YOUR_ACCESS_TOKEN" \
--header "Content-Type: application/json" \
--data '{
"queryToken": "QUERY_TOKEN",
"objectIndex": 0,
"opinion": "Agree"
}'
Unless otherwise noted, errors follow this schema:
{
"ok": false,
"error": "ERROR_CODE",
"message": "Human-readable description"
}
| Field | Type | Description |
|---|---|---|
ok |
boolean | false on error. |
error |
string | Machine-readable error code suitable for application handling. |
message |
string | Human-readable English description. Do not rely on exact wording for program logic. |
| Error code | HTTP | Description |
|---|---|---|
invalid_client |
401 | client_id or client_secret is missing, incorrect, or of the wrong type. |
auth_token_expired |
401 | Bearer token expired; request a new token. |
auth_token_invalid |
401 | Bearer token missing, malformed, or invalid. |
| Error code | HTTP | Description |
|---|---|---|
unsupported_file_format |
415 | Request body is not a recognized image format. Also returned for empty bodies, base64-encoded text, and multipart form-data. |
malformed_file |
415 | Image bytes are corrupt, truncated, or cannot be decoded as a supported format. |
image_dimensions |
422 | Image is smaller than the 32 × 32 pixel minimum. |
bad_recognition_option |
400 | A Fishial-* recognition header has an invalid value. |
credits_insufficient |
— | Account has insufficient API credits. |
| Error code | HTTP | Description |
|---|---|---|
query_token_invalid |
401 | queryToken is expired, invalid, or fails any other feedback validation check. This is the catch-all for most feedback failures (wrong field types, out-of-range values, invalid opinion values, etc.). |
Fully malformed requests — missing required fields, broken JSON, missing Content-Type — return HTTP 400 rather than a structured feedback error code.
Some responses from the edge proxy or framework — notably HTTP 400, 413, and 5xx — may return a non-JSON body (HTML or plain text) and may not follow the standard error schema above. Clients must handle non-JSON error responses gracefully rather than assuming every error parses as JSON.
curl --request POST \
--url https://api-recognition.fishial.ai/v2/auth \
--header 'Content-Type: application/json' \
--data '{
"client_id": "YOUR_CLIENT_ID",
"client_secret": "YOUR_CLIENT_SECRET"
}'
curl --request POST \
--url https://api-recognition.fishial.ai/v2/recognize \
--header "Authorization: Bearer YOUR_ACCESS_TOKEN" \
--header "Content-Type: image/jpeg" \
--data-binary @fish.jpg
curl --request POST \
--url https://api-recognition.fishial.ai/v2/feedback \
--header "Authorization: Bearer YOUR_ACCESS_TOKEN" \
--header "Content-Type: application/json" \
--data '{
"queryToken": "QUERY_TOKEN",
"objectIndex": 0,
"opinion": "Unsure"
}'