Skip to main content
Equaticket

Ticketing API / Errors

API error reference

Every error the v1 API returns has a stable error.code. Branch on that, never on error.message, which is written for humans and can change. Each error response also carries a doc_url that links straight to its section on this page, and a request_id worth quoting to support.

{
  "error": {
    "code": "missing_venue_contact",
    "message": "Add a contact email for attendees before publishing",
    "request_id": "req_01J...",
    "doc_url": "https://equaticket.com/ticketing-api/errors#missing_venue_contact"
  }
}

Authentication

missing_auth

HTTP 401

No Authorization header was sent, or it was not a Bearer token.

What to do: Send Authorization: Bearer sk_live_... (or sk_test_...) on every request. This is not a retryable condition: retrying the same request without the header returns the same error.

invalid_api_key

HTTP 401

The token was not in the sk_live_ / sk_test_ format, or no API key matching it exists.

What to do: Check the key was copied whole and has no trailing whitespace. Keys are shown once at creation; if you no longer have it, create a new key in Settings and revoke the old one.

key_revoked

HTTP 401

The API key exists but has been revoked.

What to do: Create a new key in Settings and update your integration. Revocation is permanent, so a revoked key cannot be reinstated.

Authorization

insufficient_scope

HTTP 403

The key authenticated, but does not carry the scope this endpoint requires. The response includes a required field naming the missing scope.

What to do: Read error.required, then create a key with that scope. Scopes are fixed at creation, so an existing key cannot be widened.

csrf_error

HTTP 403

A state-changing request failed the Origin/Referer check. This affects browser/session-authenticated calls, not Bearer-token API calls.

What to do: Server-to-server integrations should use an API key rather than forwarding browser cookies. If you are calling from a browser, ensure the request originates from an allowed origin.

subscription_blocked

HTTP 403

The organization's subscription is past due, paused, or otherwise not in good standing.

What to do: Resolve billing in the dashboard. Writes stay blocked until the subscription is active again. Reads are unaffected.

capacity_exceeds_plan

HTTP 403

The event's total capacity is larger than the current plan allows.

What to do: Reduce capacity_total or the ticket type quantities, or upgrade the plan. The message names the applicable limit.

ticket_limit_reached

HTTP 403

The organization has reached its plan's ticket allowance for the current window.

What to do: Upgrade the plan, or wait for the rolling window to refresh. The message states the limit and the window length.

timed_entry_disabled

HTTP 403

A timed-entry (series/slot) endpoint was called while the FEATURE_TIMED_ENTRY flag is off.

What to do: This is a platform-level flag, not an account setting. Contact support if you need timed entry enabled.

terms_acceptance_required

HTTP 403

Publishing was attempted before an owner or admin accepted the current platform documents.

What to do: Have an owner or admin sign in and accept the updated terms. API keys authenticate an organization rather than a person, so this cannot be cleared over the API.

email_not_verified

HTTP 403

A Free-tier organizer attempted to publish before verifying their email address.

What to do: Verify the address from the confirmation email. This check is skipped for API-key callers, so you will normally see it only on dashboard-authenticated calls.

Request validation

validation_error

HTTP 400 / 422

The request body failed schema validation. error.details carries a per-field array of { field, message }, and error.message repeats the first one. Returned as 422 by the shared apiValidationError helper; one public slots endpoint returns 400.

What to do: Read error.details rather than error.message, which is only the first issue. Fix every listed field before retrying, since validation is not incremental.

invalid_json

HTTP 400

The request body was not parseable JSON.

What to do: Check for a truncated body, a missing Content-Type: application/json, or double-encoded JSON (a JSON string containing JSON).

invalid_param

HTTP 400

A query-string parameter was malformed, such as a non-integer limit or an unparseable date filter. error.param names it.

What to do: Read error.param and correct that one parameter.

missing_param

HTTP 400

A required query-string parameter was absent. error.param names it.

What to do: Supply the named parameter. See the endpoint reference for which are required.

invalid_cursor

HTTP 400

The cursor pagination value was not a cursor this endpoint issued, or was corrupted in transit.

What to do: Do not construct or edit cursors. Pass back the next_cursor from the previous page verbatim, and restart from the first page if you no longer have it.

invalid_url

HTTP 400

A supplied URL failed validation. For webhook endpoints this includes the SSRF guard, which rejects private, loopback and link-local addresses.

What to do: Use a publicly resolvable HTTPS URL. Localhost and private-range addresses are rejected by design; use a tunnel during development.

limit_exceeded

HTTP 400

A per-organization cap was reached. Webhook subscriptions are capped at 5 per organization.

What to do: Delete a subscription you no longer need before creating another.

location_mode_conflict

HTTP 422

Venue fields (venue_name, venue_address, city, state_province, country) were sent for an event whose location is online or tba.

What to do: These are rejected rather than silently dropped, so a 200 never hides a write that did not happen. Omit them, or move the event back to a venue location first. Note venue_contact_email is NOT a venue field: it is the attendee contact address, is required in every location mode, and is always accepted.

Not found

not_found

HTTP 404

The addressed resource does not exist, or belongs to a different organization, or does not match the key's mode.

What to do: Confirm the id and that you are using the right key. A live key cannot see test-mode data and a test key cannot see live data, which reads as a 404 rather than a 403 so that ids cannot be probed across modes.

resource_not_found

HTTP 404

A nested resource in the path does not exist under its parent, such as a ticket type id that is not on the given event.

What to do: Verify the parent and child ids belong together. Both are checked, so a valid child under the wrong parent still 404s.

Conflicts

duplicate_slug

HTTP 409

An event with this slug already exists in the organization.

What to do: Slugs are unique per organization and permanently locked once an event is published or paused. Choose another slug, or duplicate the event to get a new URL.

event_not_editable

HTTP 409

The event is cancelled, completed, or archived, none of which accept updates.

What to do: This is terminal for that event. Duplicate it if you need an editable copy.

field_locked

HTTP 409

A field that is locked in the event's current status was modified. On a published or paused event that covers title, starts_at, ends_at, slug, currency and timezone.

What to do: Pause the event first: pausing is the unpublish step and unlocks the date fields. slug stays locked on both published and paused events. Sending a field's existing value is not a change and never 409s.

has_sales

HTTP 409

A ticket type with completed sales was deleted, or its price was changed after the first sale.

What to do: Sold ticket types cannot be deleted or repriced, because issued tickets reference them. Reduce the quantity to stop further sales (the floor is quantity_sold + quantity_reserved) and create a new ticket type at the new price.

invalid_transition

HTTP 409

The requested status change is not legal from the event's current status.

What to do: Check the current status before acting. Publishing applies to draft and paused events only, and cancelling applies to published events only.

Idempotency

invalid_idempotency_key

HTTP 400

The Idempotency-Key header was longer than 256 characters.

What to do: Use a UUID v4. Keys are scoped per API key and expire after 24 hours.

idempotency_key_reuse

HTTP 422

This Idempotency-Key was already used for a request with a different method, path, or body.

What to do: Generate a fresh key for a different operation. Reuse is refused rather than served from cache, so a key cannot silently return another request's response.

idempotency_key_in_progress

HTTP 409

A request with this key is being processed right now.

What to do: Wait briefly and retry the identical request; the completed response will replay. The in-progress lock expires after 60 seconds, so a crashed request cannot wedge a key permanently.

Rate limiting

rate_limited

HTTP 429

The plan's per-minute request limit was exceeded. Limits run from 60 requests/min on Free to 600/min on Pro.

What to do: Back off and retry using the Retry-After and X-RateLimit-Reset response headers rather than a fixed sleep. Authenticated API rate limiting fails closed, so this can also appear during a rate-limiter outage; treat it as retryable either way.

Publishing

missing_venue_contact

HTTP 422

The event has no venue_contact_email. It is required to publish in ALL THREE location modes, including online and to-be-announced.

What to do: Set venue_contact_email on the event, via POST /api/v1/events or PATCH /api/v1/events/{id}, then publish. Despite the name it is not a venue field: it is the contact address for attendees and the reply-to on ticket emails.

unsupported_currency

HTTP 422

The event currency is not one the connected Stripe account supports. The message lists the currencies that are supported.

What to do: Change the event currency to a supported one before publishing, or connect a Stripe account that supports it. This most often affects organizers outside the United States.

no_ticket_types

HTTP 422

The event has no non-archived ticket type.

What to do: Create at least one ticket type via POST /api/v1/events/{id}/ticket-types.

no_payment_account

HTTP 422

The event has paid ticket types but no connected Stripe account.

What to do: Complete Stripe Connect onboarding in the dashboard. Free events do not require it, so this check does not apply to them.

payment_account_capabilities_pending

HTTP 422

Stripe is still enabling charges or payouts on the connected account.

What to do: Wait for Stripe to finish verification and retry. This usually clears without any action, but check the Stripe dashboard if it persists.

payment_account_inactive

HTTP 422

The connected Stripe account is disconnected or disabled.

What to do: Reconnect the account in the dashboard, then publish.

requirements_past_due

HTTP 422

Stripe has outstanding requirements past due on the connected account.

What to do: Open the Stripe dashboard and supply the requested information. Publishing stays blocked until Stripe clears the requirement.

Organizer fees

org_fee_pending_approval

HTTP 403

The event's organizer-fee configuration is above the auto-approval cap and awaiting review.

What to do: Wait for approval, or lower the fee below the cap, which is the greater of the processing-recovery rate and 8 percent. Changing a ticket price after approval invalidates it and forces re-approval.

org_fee_non_us_blocked

HTTP 403

The connected account's country is outside the United States and has not been added to the organization's approved fee regions, while the event has fees configured.

What to do: Contact support to have the country approved, or set the event's fee mode to none. payment_accounts.country is the source of truth here, not the event address.

org_fee_over_max

HTTP 422

A ticket price change pushed the organizer fee above the manual review threshold, the lesser of 15 percent and 10 dollars.

What to do: Lower the fee or raise the ticket price so the fee falls under the threshold. Saves above it are blocked outright rather than queued for review.

org_fee_free_ticket_conflict

HTTP 422

A fee is configured on a ticket type priced at zero.

What to do: Remove the fee from free ticket types, or give the ticket type a non-zero price.

Server

internal_error

HTTP 500

An unhandled error occurred while processing the request.

What to do: Retry with backoff. If it persists, contact support with the request_id from the response body or the X-Request-Id header, which lets us find the exact request.

insert_failed

HTTP 500

The record could not be written.

What to do: Safe to retry with the same Idempotency-Key: nothing was created. Report the request_id if it persists.

service_unavailable

HTTP 503

A dependency needed to serve the request was temporarily unreachable, most often the credential lookup during authentication.

What to do: Retry with backoff, honouring Retry-After. Do NOT rotate your API key: a 503 says we could not check the key, not that the key is wrong.

query_error

HTTP 500

A read query failed while fetching the resource or its related records.

What to do: Retry with backoff. Reads are side-effect free, so retrying is always safe.

update_failed

HTTP 500

The record could not be updated.

What to do: Re-read the resource before retrying to confirm whether the write landed, then retry if it did not.

delete_failed

HTTP 500

The record could not be deleted.

What to do: Re-read to confirm the current state, then retry. Deletes are idempotent in effect.

Still stuck?

Quote the request_id from the error body, or the X-Request-Id response header. It identifies the exact request in our logs, which is the fastest route to an answer.