---
title: "Stripe Webhook"
method: POST
path: "/api/v1/stripe/webhook"
tags: ["stripe"]
---

# Stripe Webhook

`POST /api/v1/stripe/webhook`

## Request

- Base URL: `https://api.badgeia.com`
- URL: `https://api.badgeia.com/api/v1/stripe/webhook`
- Auth: none declared

Handle Stripe webhook events.

Currently handled:
  - customer.subscription.created
  - customer.subscription.updated
  - customer.subscription.deleted
  - customer.subscription.pending_update_applied
  - customer.subscription.pending_update_expired
  - account.updated  (Stripe Connect Express — mirrors a seller's
    charges_enabled / payouts_enabled capability flags onto the User)
  - checkout.session.completed  (F-01 Increment 2 — marketplace destination
    charge confirmed: mint the hired clone, flip the purchase
    AWAITING_PAYMENT → COMPLETED, record realized revenue, fire playbook_hired)
  - checkout.session.expired / .async_payment_failed  (flip
    AWAITING_PAYMENT → FAILED so the buyer can retry; no clone)

Returns:
  - 200 with `{"status": "ok", "event_type": ..., "deduplicated": false}`
    on first-time processing.
  - 200 with `{"status": "ok", "deduplicated": true}` on a replay
    (so Stripe stops retrying).
  - 400 on signature failure / malformed payload / malformed signature
    header (no body, missing header, expired timestamp, bad HMAC).
  - 503 with detail "Stripe not configured" when the env secret is
    unset (matched by the Sentry allowlist — see rule #7).

## Response `200`

Successful Response

- object

---

[API](https://skmtc.dev/badgeia/apis/badge.md) · [All operations](https://skmtc.dev/badgeia/apis/badge/llms.txt) · [OpenAPI document](https://skmtc.dev/badgeia/apis/badge/revisions/7e7f7fee8b77?raw)
