Errors

Every non-success response uses a single, predictable envelope. Readcode to branch behaviour, and show the human-readablemessage to your operators.

Error envelope

{
  "code": "INVALID_SIGNATURE",
  "message": "Invalid X-Signature header.",
  "correlationId": "01J7XKQE4E30000000000000"
}

Every response — success or failure — includes anX-Correlation-Id response header. Log it. If you need partner support to trace a specific call, that correlation id lets us find the exact request in seconds.

HTTP status conventions

StatusMeaning
200 OKSynchronous success.
400 Bad RequestMalformed request or permanent client error — do not retry.
401 UnauthorizedAPI key, signature, or connection state invalid.
422 Unprocessable EntityBusiness rule declined a synchronous write (redemption validation) — planned, no live endpoint returns 422 yet.
503 Service UnavailableIntegration paused or receiver not ready — retry per your backoff schedule.

Error codes

codeStatusMeaning
MISSING_API_KEY401X-Api-Key header absent.
INVALID_API_KEY401API key unknown, revoked, or from the wrong environment.
INVALID_SIGNATURE401HMAC signature does not match the raw body under any active signing secret.
SIGNATURE_EXPIRED401Signature timestamp outside the 5-minute tolerance window.
INTEGRATION_NOT_CONNECTED401Merchant has never activated the integration.
INTEGRATION_ALREADY_DISCONNECTED401Merchant disconnected the integration. Fresh credentials required.
INTEGRATION_PAUSED503Merchant paused the integration. Retry per your backoff schedule.
MISSING_IDEMPOTENCY_KEY400Planned. Reserved for the upcoming synchronous write endpoints (redemption validate/confirm, refund check). The current /events endpoint deduplicates on eventId and needs no Idempotency-Key. See Idempotency.
UNKNOWN_EVENT_TYPE400eventType is not a value the receiver recognises.
INVALID_PAYLOAD400Event body is not valid JSON or is missing required fields.
INVALID_REQUEST400Query parameters are invalid — e.g. neither or both of phone and customerId on customer lookup.
EVENT_HANDLER_NOT_REGISTERED503Event type is legitimate but the receiver has not deployed a handler yet. Retry per your backoff schedule — a later delivery will succeed.
WRONG_EVENT_DIRECTION400Event type is emitted by Quroosh (outbound webhook) and must not be POSTed to /events. Stop retrying.

Event processing codes

Returned from POST /events when an event fails its business checks. A 400 means the event cannot be processed as sent. For payload defects, fix the data and send a new event. For the state-dependent codes (unconfirmed branch mapping, missing customer mapping, frozen customer, inactive program or card), you may instead redeliver the same event after the merchant fixes their setup — failed deliveries are never cached, so a redelivery is processed fresh. A 503 means retry per your backoff schedule.

codeStatusMeaning
CUSTOMER_MAPPING_NOT_FOUND400No mapping for externalCustomerId — send CustomerSynced first.
BRANCH_MAPPING_NOT_FOUND400No mapping for externalBranchId — send BranchSynced first.
BRANCH_MAPPING_UNCONFIRMED400The branch is known but the merchant has not confirmed the pairing in the Quroosh dashboard yet.
CUSTOMER_INACTIVE400The customer is frozen for this store.
MISSING_STAMP_CARD_ID400earnType = "Stamps" without a stampCardId.
STAMP_CARD_NOT_FOUND400stampCardId is unknown for this store.
STAMP_CARD_INACTIVE400The stamp card is deactivated.
STAMP_CARD_FREE_ENTRY_ONLY400The card's only earning method is FreeEntry — it can never be credited from a partner invoice.
NO_ACTIVE_POINTS_PROGRAM400The store has no active points program.
NO_ACTIVE_EARNING_METHOD400The points program or stamp card has no active earning method.
PARTNER_INVOICE_ALREADY_EARNED400This externalInvoiceId was already credited — rejected even under a new eventId.
SUBSCRIPTION_LAPSED503The merchant's Quroosh subscription is not active. Retry — a delivery after renewal succeeds.
CONCURRENCY_CONFLICT503A concurrent ledger update collided with this event. Retry.