Skip to content

Errors

All AvailEngine errors follow a consistent format.

Error Format

json
{
  "error": {
    "code": "string",
    "message": "string"
  }
}

HTTP Status Codes

StatusMeaning
200Success
201Created
400Bad request — check your payload
401Unauthorized — invalid or missing API key
402Payment Required — developer's subscription is past due
403Forbidden — key lacks required scope
404Not found
409Conflict — duplicate idempotency key or resource clash
422Validation error — body doesn't match schema
429Too many requests — rate limit exceeded. Check Retry-After header

Error Codes

CodeMeaning
invalid_tokenAPI key or JWT is missing, expired, or malformed
missing_scopeAPI key doesn't have the required scope for this endpoint
insufficient_permissionsDashboard user doesn't have the required role
not_foundResource doesn't exist or doesn't belong to this business
validation_errorRequest body failed Pydantic validation
rate_limit_exceededKey's RPM limit reached
payment_requiredDeveloper's account is past due
conflictResource already exists (e.g. duplicate slug)
slot_unavailableRequested time slot is already booked
outside_operating_hoursBooking time is outside business hours
idempotency_mismatchSame idempotency key with different request body

Example

bash
curl https://api.availengine.com/v1/availability/nonexistent \
  -H "Authorization: Bearer avail_test_invalid"

# 401
{
  "error": {
    "code": "invalid_token",
    "message": "Could not validate credentials"
  }
}

Recovery Guide

What to do when you get each error.

invalid_token (401)

Cause: Missing, expired, or malformed API key or JWT.

Fix:

  1. Check the Authorization header is present and starts with Bearer
  2. API keys must start with avail_live_ or avail_test_
  3. JWT tokens expire after 1 hour — refresh via Supabase Auth
  4. Verify the key hasn't been revoked (GET /v1/manage/api-keys)

missing_scope (403)

Cause: Your API key doesn't have the required scope for this endpoint.

Fix:

  1. Check the key's scopes: GET /v1/manage/api-keys
  2. Create a new key with the needed scope (read or write)
  3. Most public endpoints need read. Booking creation needs write.

insufficient_permissions (403)

Cause: Your user role doesn't allow this action.

Fix:

  1. Dashboard users need business_owner or staff_member role
  2. Developer endpoints need developer role
  3. Check app_metadata.role in the JWT payload

rate_limit_exceeded (429)

Cause: Your API key has exceeded its requests-per-minute limit.

Fix:

  1. Check the Retry-After header — it tells you how many seconds to wait
  2. Implement exponential backoff in your client
  3. Create a new key with a higher RPM limit
  4. Batch requests where possible (e.g., check availability for multiple dates client-side)

payment_required (402)

Cause: Your developer subscription is past due.

Fix:

  1. Go to the Developer Portal → Billing
  2. Update your payment method
  3. Pay the outstanding invoice
  4. API access resumes automatically after payment

not_found (404)

Cause: The resource doesn't exist or doesn't belong to your business.

Fix:

  1. Verify the ID/UUID is correct (not truncated or mistyped)
  2. API keys are scoped to one business — you can't access another business's data
  3. Check if the resource was deleted or deactivated

conflict (409)

Cause: State conflict — booking status transition not allowed, or duplicate resource.

Fix:

  1. Status transitions: Check the booking lifecycle — you can't go completed → cancelled
  2. Duplicate slug: Choose a different business name
  3. Resource in use: Cancel future bookings before deleting a resource

validation_error (422)

Cause: Request body failed validation.

Fix:

  1. Read the error message — it includes which field failed and why
  2. Check field constraints: strings have min/max lengths, dates must be YYYY-MM-DD, etc.
  3. The response body includes details about each failing field

slot_unavailable

Cause: The requested time slot is already booked or outside availability.

Fix:

  1. Re-fetch availability: GET /v1/availability/{business_id}
  2. Try a different time or resource
  3. The slot may have been taken between your availability check and booking attempt

outside_operating_hours

Cause: The booking time is outside the business's operating hours.

Fix:

  1. Check operating hours: GET /v1/public/hours/{business_id}
  2. Respect last_booking_time — a 2-hour booking can't start at last_booking_time
  3. Check for blackout dates: GET /v1/public/blackout-dates/{business_id}

idempotency_mismatch (409)

Cause: Same idempotency key, different request body.

Fix:

  1. Use a unique idempotency key for each distinct operation
  2. If you're retrying the same operation, send the exact same body
  3. Generate a new key if the request details changed

Idempotency

All POST and PATCH endpoints accept an optional Idempotency-Key header. Send the same key with the same request to safely retry without duplicating side effects.

bash
curl -X POST https://api.availengine.com/v1/bookings/ \
  -H "Authorization: Bearer avail_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: unique-key-per-operation" \
  -d '{ ... }'

Responses are cached for 24 hours. If you send the same key with a different body, you get 409 with code idempotency_mismatch.

Best Practices

  • Generate a UUID for each booking creation request
  • Use the same key when retrying after a network error
  • Don't reuse keys across different operations
  • Store the key alongside the booking until you get a response

Released under the MIT License.