Skip to content

Stripe webhook — idempotent, settled-only crediting (PUBLIC).

POST
/api/billing/webhook
curl --request POST \
--url https://api.tradr.cloud/api/billing/webhook \
--header 'Content-Type: application/json' \
--data '{}'

PUBLIC endpoint (NO session auth — Stripe is the caller) and IP-rate limited. Reads the UNMODIFIED RAW request body and verifies the Stripe-Signature header against STRIPE_WEBHOOK_SECRET over the exact raw bytes (REQ-3.1) — an invalid or missing signature returns 400 and no wallet is touched. The verified event is dispatched to the idempotent settled-only handler; its outcome maps to 200 (credited / acked / duplicate / refused / reversed — terminal, Stripe stops retrying) or a retryable 5xx (transient verify-failure, no row written — Stripe redelivers). NOTE: this route MUST receive the raw body before any JSON parse; a global JSON body parser would silently break signatures.

Raw Stripe event JSON (verified by signature, not parsed by the framework).

Media typeapplication/json
object
Examplegenerated
{}

Event acknowledged (credited / acked / duplicate / refused / reversed).

Missing/invalid signature or Stripe unconfigured — no wallet touched.

Transient verify-failure — Stripe should redeliver.