Errors
What ServFlo's error answers look like, every status code and code, and what to do about each.
When a call fails, ServFlo answers with an HTTP status and a JSON body that says what went wrong in words you can show to a person:
{
"defined": false,
"code": "PLAN_UPGRADE_REQUIRED",
"status": 402,
"message": "This needs the Pro plan or higher. Upgrade in Settings → Billing.",
"data": {
"feature": "equipment_tracking",
"requiredPlan": "pro",
"requiredAddon": null,
"currentPlan": "grow"
}
}codeis stable: branch on it, not on the message.messageis written for people. It often says what to do next.datacarries details for some codes (below). It may be missing.
Status codes
| Status | Code | What it means | What to do |
|---|---|---|---|
| 400 | BAD_REQUEST | The input is not valid: a missing field, a wrong format, a value out of range, or a rule the record breaks. | Fix the input. For validation errors, data.issues lists each field. |
| 401 | UNAUTHORIZED | No credential, or the key is wrong, revoked or expired. | Check the Authorization: Bearer sfk_… header. Make a new key if this one was revoked. |
| 402 | PLAN_UPGRADE_REQUIRED | The business's plan doesn't include this (the API itself needs Pro). | Upgrade, or add the add-on named in data.requiredAddon. |
| 402 | PLAN_LIMIT_REACHED | A plan limit is used up: AI credits this month, texts past the monthly cap, or every office user seat is taken. | Buy AI credits, wait for the month to reset, or add a seat in Settings → Billing. |
| 402 | SUBSCRIPTION_REQUIRED | The ServFlo subscription has ended, so the business is read-only. Reads still work. | The owner chooses a plan in Settings → Billing. |
| 402 | PAYMENT_METHOD_REQUIRED | The business is on a free trial with no card, and this would cost money (texts, numbers, calls, campaigns…). | The owner adds a card in Settings → Billing. Nothing is charged until the trial ends. |
| 402 | BILLING_UNAVAILABLE | ServFlo can't check the plan right now, so anything that costs money is paused. | Try again in a few minutes. |
| 403 | FORBIDDEN | Your role, the key's permissions or its access level don't allow this, or a key can't do it at all. | Read the message: it names the missing permission or scope. See Authentication. |
| 404 | NOT_FOUND | No such record in this business (or one your role can't see). | Check the id and the business id in the path. |
| 409 | CONFLICT | The record's state doesn't allow it (an invoice already paid, a duplicate), or an Idempotency-Key clash. | Read the record again, then decide. |
| 409 | APPROVAL_DECLINED | You declined this call in ServFlo. | Don't retry unless you change your mind. |
| 409 | APPROVAL_EXPIRED | The approval request expired before it was approved or used. | Call again without the approval header to ask again. |
| 409 | APPROVAL_ALREADY_RUN | That approval was already used. An approval runs once. | Read the record to see the result. |
| 409 | CONFIRMATION_INVALID | The approval header doesn't match this exact call (other inputs, endpoint, key or business). | Repeat the call exactly as it was approved, or ask again. |
| 413 | PAYLOAD_TOO_LARGE | The request body is over 40 MB. | Send less, or upload files by URL. |
| 428 | APPROVAL_REQUIRED | This action waits for a person's approval in ServFlo. Nothing was done yet. | See Approvals. |
| 429 | TOO_MANY_REQUESTS | Too many calls in a minute. | Slow down and retry. See Rate limits. |
| 500 | INTERNAL_SERVER_ERROR | Something broke on our side. It is reported to us automatically. | Retry later. Use an Idempotency-Key on writes so a retry is safe. |
| 503 | SERVICE_UNAVAILABLE | A part of ServFlo is briefly unavailable. | Retry in a moment. |
Validation errors
A 400 from input validation lists every problem in message (field: what's wrong; …) and
in data.issues, with the path to each field:
{
"code": "BAD_REQUEST",
"status": 400,
"message": "scheduledDate: Use a date as YYYY-MM-DD",
"data": {
"issues": [{ "path": ["scheduledDate"], "message": "Use a date as YYYY-MM-DD" }]
}
}Plan errors in detail
402 PLAN_UPGRADE_REQUIRED names what's needed in data:
| Field | Meaning |
|---|---|
feature | The feature the call needs, such as memberships or phone. |
requiredPlan | The cheapest plan that has it (connect, grow, pro), or null for an add-on-only feature. |
requiredAddon | The add-on that sells it (phone, ai_receptionist, service_reports…), or null. |
currentPlan | The plan the business is on. |
402 PLAN_LIMIT_REACHED has data.feature (ai_credits, sms, office_users…) and
data.reason. 402 PAYMENT_METHOD_REQUIRED has data.kind (what would cost money) and
data.action: "add_card".
Reads are not blocked by the plan: after a downgrade you can still read and export what you made. A few reads that are a paid feature themselves (Customer 360 lists, job costing, weather, capacity planning, payroll runs, ads and call reports) do need it.
Approval errors in detail
428 APPROVAL_REQUIRED carries what you need to finish the call in data:
| Field | Meaning |
|---|---|
status | APPROVAL_PENDING. |
approvalId | The request's id. |
token | The value to send back in the X-ServFlo-Approval header, sfc_…. |
summary | What the person is asked to approve, in words. |
expiresAt | When the request expires if nobody decides. |
approvalUrl | The ServFlo page where the person approves it. |
header | X-ServFlo-Approval. |
See Approvals for the whole flow.