Errors
Every error response from the Aware Public API uses the same JSON envelope:
{ "type": "CheckinNotFoundError", "message": "Checkin Not Found! No checkin found with id: 8f5b9a4d-3c2e-4b1f-9d8a-72e6c1f0a4b3"}type is a stable, machine-readable string (the error class name, except where noted below). message is human-readable and may change wording across releases. Some errors include an errorId for support correlation — see below.
BadRequestError may also include an errors array of { field, message } when validation failed on specific fields.
The fixed public types
Section titled “The fixed public types”| HTTP | type | When you’ll see it |
|---|---|---|
| 400 | BadRequestError | A request field failed validation (missing, wrong type, out of range). |
| 401 | UnauthorizedError | Missing or invalid Authorization: Bearer JWT. |
| 403 | ForbiddenError | Authenticated caller is not allowed to perform this operation. |
| 404 | NotFoundError | Generic “we don’t have that, or you can’t see it”. |
| 404 | CheckinNotFoundError | A specific check-in lookup found nothing in the caller’s scope. |
| 404 | NoBreaksOnCheckinError | A break lookup found no breaks on that check-in. |
| 404 | PersonNotFoundError | A specific person lookup found nothing in the caller’s scope. |
| 404 | LabelNotFoundError | A specific label lookup found nothing in the caller’s scope. |
| 409 | IdempotencyConflict | The same Idempotency-Key is already in flight on this endpoint. |
| 409 | LastBreakAlreadyEndedError | Tried to end a break that’s already ended. |
| 409 | NoActiveBreakToEndError | Tried to end a break but the check-in has no active break. |
| 409 | ExitBeforeEntryError | Checkout timestamp is before the check-in entry time. |
| 429 | RateLimited | Rate limit exceeded. See Rate limits. |
| 503 | ServiceUnavailable | A dependency required to complete the request is temporarily unavailable. |
| 500 | Internal | Unexpected server failure. Includes errorId; send it to support. |
This list is closed for /v1. We don’t add new type values without a Changelog entry, and we never remove or rename one in /v1.
Mapping to your own error model
Section titled “Mapping to your own error model”A simple, robust client-side mapping:
if (res.ok) return res.json()
const err = (await res.json()) as { type: string message: string errorId?: string errors?: { field: string; message: string }[]}
switch (err.type) { case 'BadRequestError': throw new BadRequestError(err.message, err.errors) case 'UnauthorizedError': case 'ForbiddenError': throw new AuthError(err.message) case 'CheckinNotFoundError': case 'NoBreaksOnCheckinError': case 'PersonNotFoundError': case 'LabelNotFoundError': case 'NotFoundError': throw new NotFoundError(err.message) case 'IdempotencyConflict': case 'LastBreakAlreadyEndedError': case 'NoActiveBreakToEndError': case 'ExitBeforeEntryError': throw new ConflictError(err.message) case 'RateLimited': throw new RetryLaterError(err.message, res.headers.get('Retry-After')) case 'ServiceUnavailable': throw new RetryLaterError(err.message, res.headers.get('Retry-After')) case 'Internal': throw new InternalError(err.message, err.errorId) default: throw new UnknownAwareError(err.type, err.message)}You can safely treat any type you don’t recognise as “unknown error from Aware” — we won’t introduce a new one in /v1 without a Changelog entry, but tolerant clients are still a good habit.
Internal errors and errorId
Section titled “Internal errors and errorId”Anything we can’t classify becomes:
{ "type": "Internal", "message": "An unexpected error occurred.", "errorId": "3f2a..."}The errorId is unique to that request. Send it to Aware support and we can find the corresponding log entry.
Common pitfalls
Section titled “Common pitfalls”BadRequestErroris for shape, not domain rules. A missing required field isBadRequestError. Trying to end a break that’s already ended isLastBreakAlreadyEndedError(409), notBadRequestError.404vs403. When your caller cannot see a resource that exists, we deliberately return404rather than403. This stops probing for resources outside authorized scope.- Always read
Retry-After. Don’t infer back-off from the message — parse the header.