Skip to main content
Version: 0.1.0

Retorna Gateway β€” Webhooks

Events Retorna Gateway sends to you. Everything else in these docs describes endpoints you call; this one describes the endpoint you expose and we call.

Today there is exactly one event: an order changed state.

Registering your endpoint​

The URL (https only) is set when your organization is provisioned, and the same step hands you the webhookSecret β€” the key you verify signatures with. Ask us to point it somewhere else if it has to move.

webhookSecret is revealed once and never again. It is not recoverable from any endpoint. Store it the moment you receive it; if you lose it, the webhook has to be re-provisioned.

Verifying the signature β€” do this before anything else​

Every delivery carries an X-Retorna-Signature header: the HMAC-SHA256 of the raw request body, hex-encoded, keyed with your webhookSecret.

Hash the bytes you received. Do not parse the JSON and re-serialize it first β€” key order and whitespace would change and the signature would not match. Most frameworks expose this as a "raw body" or "buffer body".

import hmac, hashlib

def is_authentic(raw_body: bytes, header: str, secret: str) -> bool:
expected = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, header) # constant-time on purpose

Compare in constant time (hmac.compare_digest, crypto.timingSafeEqual). A plain == leaks, byte by byte, how much of a guess was right.

Treat an unsigned or badly signed request as hostile: your endpoint is public, and the signature is the only thing separating us from anyone else who learns the URL.

Answering​

Reply 2xx once you have durably accepted the event. Anything else β€” any 4xx included β€” counts as a failure and we retry.

Answer fast: a delivery is abandoned after 10 seconds. Do the work afterwards, off the request. If you answer 2xx and then fail internally, we consider it delivered and you will not hear about that order again.

Retries, and what happens when you stay down​

A failed delivery is retried up to 3 times with exponential backoff. If all of them fail, the event goes back on our queue and the whole cycle runs up to 3 more times before the event is parked for manual inspection.

Redeliveries mean the same event can arrive more than once. Deduplicate on eventId, which is stable across every attempt at the same event.

Events are not ordered. Two changes to the same order can arrive out of sequence; trust timestamp and status, not arrival order.