# Stripe webhooks in Claude Code

Send Stripe events to your agent with the signature checked and retries deduplicated.

Stripe shows an endpoint's signing secret only after the endpoint exists, and Brynth needs the secret to create the source that gives you the URL. Create the endpoint with a temporary URL first, then point it at Brynth.

## 1. Create the Stripe endpoint

In the Stripe Dashboard, open Developers, Webhooks, and add an endpoint:

- URL: any HTTPS address for now, for example `https://example.com/`;
- events: the ones your agent handles, for example `invoice.payment_failed` and `checkout.session.completed`.

Open the endpoint and copy its signing secret, `whsec_…`.

## 2. Create the Brynth source

Ask Claude Code:

> Add a Brynth webhook source called stripe with Stripe verification. The signing secret is whsec_…

The agent calls:

```text
source_add({type: "webhook", name: "stripe", verification: "stripe", secret: "whsec_…"})
```

and gets back the source with its `url`, `https://hooks.brynth.ai/w/…`. The secret is stored encrypted and never shown again.

If you prefer the secret not to pass through the conversation, create the source with `POST /v1/sources` and the same body, using the admin key in `~/.config/brynth/credentials.json` (or in the folder `BRYNTH_CONFIG_DIR` names).

## 3. Point Stripe at Brynth

Edit the Stripe endpoint and replace the temporary URL with the source `url`. Send a test event from the Dashboard.

## 4. Handle the events

> Check my Brynth inbox for Stripe events.

```text
inbox_list({source: "stripe"})
```

Each event has the Stripe event type as `type` (for example `invoice.payment_failed`), `verified: true` and `trust: "external_untrusted"`. The agent claims an event, works on it and acks it:

```text
inbox_claim({event_id: "evt_…"})
inbox_ack({event_id: "evt_…", result: "Reminder sent to the customer"})
```

Stripe retries deliveries with the same event id; Brynth keeps one copy for 30 days. A request with a wrong signature is refused with `401` and never reaches the inbox.

To wait for the next event instead of polling: `inbox_wait({timeout_seconds: 60})`.

## Local development with the Stripe CLI

```bash
stripe listen --print-secret
```

prints the `whsec_…` secret of your Stripe CLI session. It differs from the secret of the dashboard endpoint, so create a second source with it, as in step 2 but with another name, such as `stripe-dev`, then forward events to that source's URL:

```bash
stripe listen --forward-to "https://hooks.brynth.ai/w/…"
stripe trigger invoice.payment_failed
```

The forwarded events arrive in that source: `inbox_list({source: "stripe-dev"})`.
