Skip to main content
Meow POSTs an event to your URL when a transfer changes state or a deposit clears. The wire format is Standard Webhooks: the Python, Node, and Go verifier libraries work as-is.

You’ll need

  • An API key with webhooks:write and webhooks:read.
  • A public HTTPS URL. Private, loopback, and metadata IPs are blocked at both create time and every delivery.

1. Create a subscription

Save signing_secret from the response. Meow returns it once. Every webhook POST requires an Idempotency-Key header, so a retried create never leaves you with two subscriptions. Generate a fresh key per operation: 1-50 printable ASCII characters, no spaces. Reusing one is rejected with a 400.
Response
event_types: null subscribes to everything. Pass an array to allowlist (empty array is rejected). You can only list events this subscription can receive: the rail events in the catalog plus your own onboarding events, application.* and identity_verification.* (so a global key can track an entity it is onboarding without polling). Only the delivery-meta events webhook.test and message.attempt.exhausted are rejected with a 400. They are always-on or on-demand, not subscribable.

2. Verify the signature

Three headers come with every delivery: Sign f"{webhook-id}.{webhook-timestamp}.{body}" with HMAC-SHA-256. The HMAC key is the base64-decoded body of your whsec_<base64> secret, not the raw string. Reject anything more than 5 minutes off. That is the replay window.
Use constant-time compare (hmac.compare_digest, crypto.timingSafeEqual, hmac.Equal). == leaks the secret one byte at a time.

3. Dispatch on payload.status

Event names stay coarse: {resource}.created and {resource}.updated. The lifecycle stage lives on the payload, so one handler covers the whole flow:
Per-event payload shapes are in the event catalog.

4. Pick a payload mode

Set payload_mode per subscription. Change it any time with PATCH.
data carries the full resource. No follow-up GET needed.

5. Handle out-of-order deliveries

Deliveries are not ordered. Retries, redrives, and concurrent workers mean an older state for a resource can land after a newer one. Two fields let you stay correct. Every resource event carries a sequence, a counter that increments once per resource, the same for every subscriber, stable across retries and redrives. Track the highest sequence you’ve applied per resource and advance it with a single atomic conditional write, so a stale delivery can’t overwrite newer state:
sequence is monotonic, not gapless. A hole (you see 4 then 7) is normal. Not every internal change emits an event, and a redelivered event keeps its original number. Never wait for a missing number or treat a gap as lost data; only the per-resource ordering is guaranteed.
sequence is absent on webhook.test and message.attempt.exhausted (they describe no resource). For everything else, pair it with deduplication on webhook-id (next section): sequence discards stale states, webhook-id discards exact duplicates.

6. Retries

Meow retries up to 10 times over ~91 hours.
  • Each non-zero delay gets up to 20% extra jitter.
  • Retry-After on a 429 or 503 is honored, up to 24 hours.
  • 5 failures in a row open a circuit breaker on the subscription. New deliveries wait out a cooldown (1 → 30 min) without burning an attempt. A success closes it.
  • After 10 failed attempts the subscription is auto-disabled (disabled_reason=retry_exhausted) and a message.attempt.exhausted event fires.
To recover: PATCH /webhooks/subscriptions/{id} with {"is_enabled": true}, or replay a single delivery with POST /webhooks/deliveries/{id}/redrive.

7. Operate

Send a test event

Sends webhook.test to one subscription. Good for verifying a new receiver without waiting for real activity.

Inspect delivery history

Every attempt with HTTP status and response body excerpt.

Redrive a delivery

Resets the counter and re-queues. Works even after failed_permanent.

Rotate the secret

PATCH with rotate_secret: true. Both old and new secrets sign for 7 days; pick whichever your code recognizes.

8. Security checklist

Constant-time compare. == leaks the secret.
Otherwise a leaked payload can be replayed forever.
Same event can arrive twice (retries, redrives). webhook-id doesn’t change.
Advance the highest sequence per resource with an atomic conditional write so a stale delivery can’t overwrite newer state. See Handle out-of-order deliveries.

See also