Errors & Retries
Response envelope format, HTTP status codes, and retry guidance for the FieldCamp API.
Every response carries a top-level success boolean. What sits next to it varies by
which layer answered, so write your client to read defensively:
- On success, the resource endpoints return
data, plusmetaon the list endpoints. Some endpoints also spread the payload's own fields alongsidedatafor older consumers — readdataand ignore the duplicates. - On failure, expect
messagefirst and fall back toerror; both usually carry the same string. Authentication, scope and rate-limit failures also carry a stablecode(UNAUTHORIZED,FORBIDDEN,RATE_LIMITED,INTERNAL_ERROR), while a validation message raised by an endpoint may have nocodeat all. A few older endpoints returnerroras a nested object rather than a string.
In short: branch on the HTTP status, read code when it is there, and use
message ?? error for display.
Success envelope
{
"success": true,
"data": {
"job": { "id": "job_abc123", "...": "..." }
}
}The shape of data varies by endpoint. The per-endpoint reference pages
document each one.
Error envelope
{
"success": false,
"error": "jobNumber is required"
}Status codes
| Code | Meaning | Retry? |
|---|---|---|
200 | Success | — |
400 | Validation error — fix your payload | No |
401 | Authentication failed — missing, invalid, or expired API key | No |
403 | Authorization failed — your tenant doesn't have access | No |
404 | Resource not found | No |
409 | Conflict — e.g. duplicate jobNumber | No, handle idempotently |
429 | Rate limited | Yes, with backoff |
500 | Server error | Yes, with exponential backoff |
502 503 504 | Gateway / upstream issues | Yes, with exponential backoff |
Recommended retry policy
- 5xx: retry up to 3 times with exponential backoff — 1 s, 2 s, 4 s.
- 429: same pattern; if responses include a
Retry-Afterheader, honor it. - 4xx: do not retry. Fix the payload or the auth, then re-submit.
- Network errors: retry up to 3 times with the same backoff as 5xx.
Reference implementation:
async function retryingRequest(fn, attempt = 0) {
try {
return await fn();
} catch (err) {
const status = err.response?.status;
const retryable = !status || status >= 500 || status === 429;
if (retryable && attempt < 3) {
await new Promise(r => setTimeout(r, 1000 * Math.pow(2, attempt)));
return retryingRequest(fn, attempt + 1);
}
throw err;
}
}Common errors
401 Unauthorized — Invalid or expired token
Your fc_live_ API key is missing, invalid, or expired. The v1 API accepts only fc_live_ keys — a support-issued JWT returns this error.
Check:
- You send the key in one of these, with the full
fc_live_prefix:Authorization: Bearer fc_live_...(one space, no quotes), orX-Api-Key: fc_live_...
- You are not also sending a stale
X-Api-Keyheader.X-Api-Keyis read first, so an old JWT left in that header overrides a correctAuthorizationkey and still fails with this error. Remove it. - The key has no whitespace or newlines.
Create or rotate keys yourself from Settings → API Tokens.
400 Validation error — jobNumber is required
Your POST /api/jobs payload is missing a required field. Most common
causes:
- You sent the request as JSON instead of
multipart/form-data. See the Jobs reference. jobDatacontains a JSON string, but is missing one of the required top-level fields. See the NewJobData schema.- A field name is misspelled — field names are case-sensitive.
409 Conflict — duplicate jobNumber
A job with that jobNumber already exists in your tenant. See
Idempotency for the recommended lookup-then-create
pattern so retries are safe.
500 Internal server error
Something went wrong on our side. Retry with exponential backoff. If it persists beyond three retries, capture the request ID from response headers and email support@fieldcamp.ai.
ID fields
Quirk: the same object can come back with different ID field names
across endpoints — id, recordId, or _id. Code defensively:
const resourceId =
response.data.data.resource.id ??
response.data.data.resource.recordId ??
response.data.data.resource._id;Prefer id when present. Normalization is on the roadmap.