Webhooks
Stripe billing webhooks today. Custom deal-event webhooks on the roadmap.
Scouq exposes one inbound webhook endpoint for Stripe, which keeps user plan state in sync with billing events. Outbound webhooks for deal events (new match, score change, status change) are planned for a future release.
Stripe billing webhook
The Stripe webhook lives at POST /api/stripe-webhook. Stripe posts events here whenever a checkout completes, a subscription updates, or an invoice fails. Scouq updates the user's plan field in Supabase accordingly.
This is not an endpoint you call directly. It is the receive side of a webhook that Stripe sends. The only setup work is on the Stripe dashboard.
Endpoint URL
https://scouq.com/api/stripe-webhook
Events Scouq listens for
| Stripe event | Effect |
|---|---|
checkout.session.completed | Marks the user's plan as paid based on the purchased product. |
customer.subscription.updated | Syncs plan tier and active status. |
customer.subscription.deleted | Downgrades the user back to the free tier. |
invoice.payment_failed | Flags the account for retry; access is preserved through Stripe's grace window. |
Setup
For self-hosted forks or for understanding how Scouq's billing is wired, see the full setup walkthrough in STRIPE.md at the repo root. The short version:
- In the Stripe dashboard, go to Developers, Webhooks, Add endpoint.
- Use the URL above as the endpoint URL.
- Select the four events listed above.
- Copy the signing secret Stripe generates and add it to Vercel as
STRIPE_WEBHOOK_SECRETon both Preview and Production. - Send a test event from the Stripe dashboard and confirm a
200response.
Stripe verifies webhook authenticity with HMAC signatures. The signature header is Stripe-Signature. Scouq's endpoint rejects requests whose signature does not verify against STRIPE_WEBHOOK_SECRET.
Retry behavior
Scouq's endpoint must respond with a 2xx status within Stripe's timeout (currently 30 seconds) for the event to be considered delivered. Non-2xx responses cause Stripe to retry with exponential backoff for up to three days. The endpoint is idempotent on Stripe event id, so retries are safe.
Custom outbound webhooks Planned
Outbound webhooks let your system react to events inside Scouq without polling. The planned scope:
deal.created. A new deal landed in your watchlist or matched a saved search.deal.score_changed. A deal's Scouq score moved by more than a configured threshold.deal.status_changed. A deal moved between pipeline stages (new, under contract, closed, dropped).portfolio.metric_changed. A portfolio metric crossed a user-defined trigger.
Each event will deliver a signed JSON payload to your endpoint, with an X-Scouq-Signature header containing an HMAC SHA-256 of the body. The shape will mirror the Stripe convention: a stable id, a type, and a data object.
If you have a concrete use case that should shape this design, file a request from the in-app feature request form so it can be prioritized.