SapanCalDeveloper Docs

Errors

The error format, every error code, and which errors are safe to retry.

Every error response has the same shape:

JSON
{
  "error": {
    "code": "invalid_request",
    "message": "Request validation failed.",
    "request_id": "req_8Hf2kLq9TzW1xYbN",
    "details": {
      "issues": [{ "path": "body.periods.0.end", "message": "period end must be after start", "code": "custom" }]
    }
  }
}
  • code is stable and machine-readable. Branch on it.
  • message explains the problem in plain English. It may change, so don't parse it.
  • request_id is also sent as the X-Request-Id header on every response, including successful ones. Quote it when you contact support.
  • details is only present on some errors.

Error codes

StatusCodeMeaningRetry?
400invalid_requestThe request is malformed or fails validation. details.issues lists each problem, with path like body.periods.0.end.No: fix the request.
400wrong_regionThe API key belongs to another region. See Regions and base URLs.No
401unauthorizedThe API key is missing, malformed, unknown or revoked.No
403forbiddenThe application is disabled, or Google or Microsoft refused the operation (for example writing to a read-only calendar).No
403company_suspendedThe company account is suspended.No
403connection_limit_reachedA new connection would pass the development limit. See Development and production.No
404not_foundThe user, connection, session, calendar or event doesn't exist, or belongs to another application.No
409relink_requiredThe connection needs relinking. details.connection_id says which. See Connecting calendars.After the user relinks
409conflictThe request conflicts with current state, for example the connection was revoked or the user has no default connection.No
429rate_limitedToo many requests. See Limits and rate limits.Yes, after Retry-After seconds
500internal_errorSomething went wrong on BentoCal's side.Yes, with backoff
502provider_unavailableGoogle or Microsoft failed or timed out.Yes, after Retry-After seconds

New codes may be added. Treat an unknown code by its HTTP status.

Errors inside successful responses

Free/busy and availability read many calendars at once, so one failing user doesn't fail the request. They return 200 and list failures in errors, with a code of relink_required, provider_unavailable, not_found or no_connections.

Retrying safely

After a timeout or a retryable error, you can usually repeat the request:

CallOn retry
PUT /users/{user_id}/events/{event_id}Your event id identifies the event, so a retry updates it instead of creating a second one.
DELETE /users/{user_id}/events/{event_id}Deleting an event that's already gone returns 204.
DELETE /connections/{connection_id}Revoking an already revoked connection returns 204.
DELETE /users/{user_id}Returns 404 not_found if the first attempt already deleted the user. Treat that as done.
GET, POST /free_busy, POST /availabilityThey only read.
PATCH /users/{user_id}Setting the same default twice has the same result.
POST /connect_sessionsA retry creates another session. Use the one from the response you received; unused sessions expire after 30 minutes.

Use exponential backoff with jitter, and honour Retry-After when it's present.