Errors
At the end of this guide your app reads every refusal the same way and knows what to do with each code.
The shape
Every refusal is JSON with one error object. code is stable and is what your app should branch on; message is for people and may change. field names the parameter or body field at fault, permission names a missing permission, and request_id is the same value as the Shiftly-Request-Id header.
{
"error": {
"code": "validation_failed",
"message": "end_time must be after start_time.",
"field": "end_time",
"request_id": "req_66f1c2a4b3d9e8f7a6b5c4d3"
}
}A batch create that is refused carries errors: one entry per item at fault, with its position in the batch. Nothing in a refused batch is saved.
The codes
| Code | Status | Meaning |
|---|---|---|
| invalid_request | 400 | The request is malformed: bad JSON, an unknown query parameter or a bad cursor. |
| range_too_long | 400 | The from and to dates span more days than this list allows. max_days says how many; ask for a shorter range. |
| invalid_token | 401 | The access credential is missing or malformed. |
| token_expired | 401 | The access credential has expired. Renew it with the refresh token. |
| origin_not_allowed | 403 | The request carried an Origin header, as a web page in a browser sends. Call the API from your server. |
| permission_denied | 403 | The permission was not given, the person who connected the app no longer holds it, or the connection is stopped. |
| not_available | 403 | This operation is not open to partner apps: publishing, approving, deciding leave, changing staff details or pay, changing a record another app or a manager created, or using a feature the business has switched off. |
| connection_disconnected | 403 | The business disconnected your app. Ask them to connect it again from your product. |
| connection_suspended | 403 | The connection stopped: the connecting person left, it went unused for 60 days, or a credential was reused. The business has to connect your app again. |
| app_suspended | 403 | Shiftly has paused your app for every business. Contact Shiftly. |
| ondemand_unavailable | 403 | The business hasn't set up OnDemand, so your app can't add or change OnDemand shifts there. |
| not_found | 404 | There is nothing at this address, or no such record in this business. |
| conflict | 409 | The record's state refuses the change: an ended employment, an overlapping shift or leave request, or a project code already in use. |
| shift_started | 409 | The shift has already started, so it can only be changed in Shiftly. |
| not_a_draft | 409 | The OnDemand shift has been published, so it can only be changed in Shiftly. |
| timesheet_not_pending | 409 | The timesheet has been approved, so it can only be changed in Shiftly. |
| leave_not_pending | 409 | The leave request has been decided, so it can only be changed in Shiftly. |
| idempotency_key_reused | 409 | This Idempotency-Key was already used with a different request body. |
| request_in_progress | 409 | The first request with this Idempotency-Key is still running. Try again shortly. |
| validation_failed | 422 | A field is wrong. The field property names it. |
| rate_limited | 429 | Too many requests. Retry-After says when to try again. |
| internal_error | 500 | Something went wrong at Shiftly. Quote the request id. |
| not_configured | 503 | This environment is not set up for partner apps yet. |
OAuth endpoints use the OAuth error vocabulary instead: invalid_request, invalid_client, invalid_grant, invalid_scope, unsupported_grant_type and access_denied, with an error_description.
The request identifier
Every response, success or refusal, carries a Shiftly-Request-Id header. Log it with your own request log. When you contact Shiftly about a request, quote it; it is how we find the request on our side.
What to retry
- 429: wait until the RateLimit reset, then retry the same request.
- 500 and network failures: retry with the same Idempotency-Key, so a write that did land is not repeated. See Safe retries.
- 401: renew the credential and retry once.
- Everything else: do not retry unchanged. The request will be refused again.
