Errors & responses

A consistent envelope for every response, success or failure.

Success

{
  "success": true,
  "data": { "...": "endpoint-specific payload" },
  "message": "Events retrieved successfully."
}
  • success, always true on success.
  • data, the payload. Search results wrap a header (echo of your input), a count and a results array; single-item endpoints return result.
  • message, a human-readable summary.

Failure

When a business rule fails, success is false and message explains why:

{
  "success": false,
  "message": "The selected quantity is not available for this ticket."
}

Validation errors (422)

Missing or malformed parameters are rejected with 422 before the request reaches business logic, so they do not use the envelope. Instead you get a top-level message and an errors map keyed by field. Nested fields use dot notation (for example delivery.phone):

{
  "message": "The eventId field is required. (and 1 more error)",
  "errors": {
    "eventId": ["The eventId field is required."],
    "delivery.phone": ["The delivery.phone must be a string."]
  }
}

Read errors to map each message back to the input that caused it. A field can carry more than one message, so treat each value as an array.

Authentication

Authentication failures also come back without the envelope:

{ "message": "Unauthenticated." }

Status codes

Code Meaning
200 Request succeeded. Check success in the body for business-level errors.
401 Missing or invalid bearer token.
403 The token is valid but your account is not allowed on this endpoint.
404 The resource does not exist, or does not belong to your account.
409 Conflict with the current state of the resource. Read message to tell the cases apart.
422 Validation failed. Read the errors map for the offending fields.
429 Too many requests, slow down and retry with backoff.
5xx Temporary server error, retry with exponential backoff.

A 200 status does not always mean success. Always inspect the success field, availability, pricing and split-quantity errors are reported there.

Conflicts (409)

409 means the request was well-formed but clashes with the current state. On the Seller API it covers three cases, told apart by message:

  • Duplicate external_id: a ticket with that id already exists. The response carries the existing ticket, so treat a repeated POST /broker/tickets as a safe retry.
  • Event pending approval: the event you submitted is not approved yet. Wait for the event.approved webhook before posting tickets to it.
  • Locked ticket: a buyer checkout is holding the listing, so writes are refused until the sale completes or expires. The body carries "locked": true. See Locked tickets.

On the Buyer API, POST /orders/create answers 409 when the Idempotency-Key (or the lock requestId) clashes with an earlier request. The body uses the envelope and data.code tells the cases apart:

data.code Meaning What to do
IDEMPOTENCY_IN_PROGRESS The first request with this key is still running Wait a few seconds and retry with the same key
IDEMPOTENCY_KEY_REUSED The key was already used for a different ticket, event or quantity Use a new key for a new order
IDEMPOTENCY_OUTCOME_UNKNOWN The earlier outcome could not be confirmed Do not retry. Contact support with the key

See Retry safely with an idempotency key.

Handling errors well

  • Always branch on success, not just the HTTP status.
  • On 422, read the errors map to highlight the invalid fields, and fix the input before retrying, the same request will fail again.
  • Surface message to your logs; show a friendly message to end users.
  • Retry 429 and 5xx with exponential backoff and a cap.
  • Do not loop on a 409. Fix the conflict, or queue the change for your next sync cycle. The one exception is IDEMPOTENCY_IN_PROGRESS on orders/create: wait a few seconds and retry with the same key.
  • Send an Idempotency-Key on orders/create and reuse it on every retry of the same order, so a timeout never leads to a second purchase. See the Ticket purchase flow.