---
title: "X402 Subscribe Confirm"
method: POST
path: "/v1/x402/subscribe/confirm"
---

# X402 Subscribe Confirm

`POST /v1/x402/subscribe/confirm`

## Request

- Base URL: `https://api.storyflo.com` (the document declares no server; this is the origin it was published from)
- URL: `https://api.storyflo.com/v1/x402/subscribe/confirm`
- Auth: none declared

Confirm an on-chain USDC payment for a publisher subscription.
The frontend calls this AFTER the wallet returns a successful
sendTransaction — we verify the tx on-chain (Base mainnet RPC: receipt
status + a USDC Transfer of >= the plan price to the PUBLISHER's payout
wallet) BEFORE marking the subscription active.

Trust model: the on-chain verification IS the authorization — no valid,
correctly-priced USDC payment to the publisher's payout wallet means no
activation, so guessing a ``subscription_id`` (a DB PK) buys nothing. The
receiver verified here MUST match the wallet the payer was instructed to
pay in ``listener_subscribe_publisher`` (``pub.payout_wallet_address``),
not the platform x402 receiver. The chain is pinned to base-mainnet so a
free testnet-USDC transfer cannot be passed off as payment. The ``tx_hash``
is required to be globally unused (across subscriptions and X402Payment
receipts) so a settled payment can't be replayed onto another sub.

Pool-safety: this handler does NOT take ``Depends(get_db)``. It opens a
short read session, releases it, runs the external Base-RPC verification
with NO pooled connection held, then opens a short write session — the
canonical fix for the pool-exhaustion anti-pattern
(tests/test_pool_exhaustion_static_audit.py). Holding a connection across
``_eth_get_receipt`` would be exactly that anti-pattern.

Known residual (tracked follow-up, needs a coordinated FE change): the
payment is bound to the publisher + amount but NOT to the individual
subscriber, so a same-publisher/same-tier front-runner could confirm THEIR
pending sub with a victim's just-broadcast tx. Closing it requires binding
a listener/publisher auth token on confirm (verify sub.listener_email) —
a breaking FE-contract change deferred to its bridge PR. This is strictly
narrower than the free-activation hole this fix closes.

## Request body

- X402ConfirmRequest
  - `subscription_id` string, required
  - `tx_hash` string, required
  - `chain` string

## Response `200`

Successful Response

- object

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/storyflo/apis/storyflo-inference-router.md) · [All operations](https://skmtc.dev/storyflo/apis/storyflo-inference-router/llms.txt) · [OpenAPI document](https://skmtc.dev/storyflo/apis/storyflo-inference-router/revisions/c3a1a735ac7a?raw)
