---
title: "Stripe webhook receiver — the single writer of billing state after checkout"
method: POST
path: "/api/webhooks/stripe"
tags: ["Internal"]
---

# Stripe webhook receiver — the single writer of billing state after checkout

`POST /api/webhooks/stripe`

## Request

- Base URL: `https://tre-app.com`
- URL: `https://tre-app.com/api/webhooks/stripe`
- Auth: none required

Called by Stripe, not a person or agent: authenticated by the `stripe-signature` header (an HMAC over the raw body, verified against `STRIPE_WEBHOOK_SECRET`) rather than a Tre bearer token or web session. 404s when billing is not configured on this installation (self-host); 503 when the installation has a Stripe key but no webhook secret configured yet.

## Headers

- `stripe-signature` string, required

## Response `200`

Success

- WebhookReceipt
  - `received` true, required
  - `replay` true: True when this event id was already processed (idempotent replay).

## Other responses

- `400`: Invalid request
- `401`: Unauthenticated
- `403`: Forbidden: insufficient role or token scope; scope denials name the held scope and the operation
- `404`: Not found
- `409`: Conflict
- `429`: Rate limited
- `500`: Internal server error
- `503`: Temporarily unavailable

---

[API](https://skmtc.dev/tre-app/apis/tre-rest-api.md) · [All operations](https://skmtc.dev/tre-app/apis/tre-rest-api/llms.txt) · [OpenAPI document](https://skmtc.dev/tre-app/apis/tre-rest-api/revisions/26a7187a05fc?raw)
