Skip to content
ShiftlyDevelopers
Documentation menu

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.

A refusal
{
  "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

Error codes
CodeStatusMeaning
invalid_request400The request is malformed: bad JSON, an unknown query parameter or a bad cursor.
range_too_long400The from and to dates span more days than this list allows. max_days says how many; ask for a shorter range.
invalid_token401The access credential is missing or malformed.
token_expired401The access credential has expired. Renew it with the refresh token.
origin_not_allowed403The request carried an Origin header, as a web page in a browser sends. Call the API from your server.
permission_denied403The permission was not given, the person who connected the app no longer holds it, or the connection is stopped.
not_available403This 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_disconnected403The business disconnected your app. Ask them to connect it again from your product.
connection_suspended403The 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_suspended403Shiftly has paused your app for every business. Contact Shiftly.
ondemand_unavailable403The business hasn't set up OnDemand, so your app can't add or change OnDemand shifts there.
not_found404There is nothing at this address, or no such record in this business.
conflict409The record's state refuses the change: an ended employment, an overlapping shift or leave request, or a project code already in use.
shift_started409The shift has already started, so it can only be changed in Shiftly.
not_a_draft409The OnDemand shift has been published, so it can only be changed in Shiftly.
timesheet_not_pending409The timesheet has been approved, so it can only be changed in Shiftly.
leave_not_pending409The leave request has been decided, so it can only be changed in Shiftly.
idempotency_key_reused409This Idempotency-Key was already used with a different request body.
request_in_progress409The first request with this Idempotency-Key is still running. Try again shortly.
validation_failed422A field is wrong. The field property names it.
rate_limited429Too many requests. Retry-After says when to try again.
internal_error500Something went wrong at Shiftly. Quote the request id.
not_configured503This 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.