> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.fluveo.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.fluveo.com/_mcp/server.

# Setup Intents

> **Status: `contracted_test`.** SetupIntents are in the generated API
> Reference for test-mode merchants.

The contract includes create, retrieve, update, confirm, cancel, and list under
`/v1/setup_intents`. List is a tenant-scoped Stripe list envelope from
`merchant_setup_intents`; it never returns shared processor rows. Invalid
cursors return a named 400.

This surface is test-only. `sk_live_*` issuance and live mode remain
unavailable.

**Create** accepts `payment_method=pm_*` when the PaymentMethod is owned by the
authenticated merchant in the same test/live mode and already attached to the
request `customer`. A foreign or unknown `pm_*` returns `resource_missing` with
message `No such payment_method.`. A merchant-owned `pm_*` attached to a
different customer returns a named 400 on `payment_method`; a detached one
returns Stripe's 400 with `code: "payment_method_unexpected_state"` ("This
PaymentMethod was previously used without being attached to a Customer or was
detached from a Customer, and may not be used again."). `customer` **and
`confirm=true`** are required when attaching a saved payment method on create
(omitting `confirm=true` is a named 400 on `confirm`; the processor cannot hold
an unconfirmed saved-instrument setup). `usage` is `off_session`, Stripe's
default.

**Confirm** takes the same saved `pm_*` (Stripe's two-step setup): create the
SetupIntent with its `customer`, then confirm it with `payment_method=pm_*`.
A foreign or unknown `pm_*` returns `resource_missing` on `payment_method`, a
card not attached to the SetupIntent's customer a named 400 on
`payment_method`, a detached card Stripe's 400
`payment_method_unexpected_state` (as on create), and a SetupIntent without a
customer a named 400 on
`customer`. **Update** cannot attach a saved `pm_*`: it returns a named 400 on
`payment_method` that points to the confirm. A description-only update keeps
the intent's status. A BR account answers a saved `pm_*` on create or confirm
with `payment_method_not_available`, since Cielo Zero Auth needs the security
code a saved card lacks; to save a reusable BR card, confirm a PaymentIntent
with `customer` and `setup_future_usage=off_session`, then reuse its
`payment_method`.

Public `/v1` takes no card data, `currency`, `receipt_email`,
`setup_future_usage` or `client_secret` on a SetupIntent, nor `confirm` and
`return_url` on update, `customer`, `description` and `metadata` on confirm,
any `payment_method_data[type]`, or `cancellation_reason=fraudulent`. Each
answers Stripe's 400: `Received unknown parameter: <param>` with
`code: "parameter_unknown"`, or an invalid value on its `param`.

On a US account, create with a saved `pm_*`, its `customer` and `confirm=true` sets the card up again
and returns `succeeded` (or `requires_action` when the issuer asks for
authentication), as Stripe does. A two-step confirm with the saved `pm_*`
does the same. A saved `pm_*` this account cannot set up again returns a named
400 on `payment_method`.

## Hidden from the public API

Each item below is hidden because it does not follow the Stripe parity ADR (ADR 0004 as amended). The [hidden public `/v1` registry](https://github.com/fluveohq/fluveo/blob/main/tests/api-contract/stripe/hidden-public-v1.json) lists every
hidden item. Public `/v1` answers a hidden operation as an unknown URL, refuses a hidden request
parameter or value with Stripe's `invalid_request_error`, and omits a hidden response key.

* the value `fraudulent` of `cancellation_reason` on `POST /v1/setup_intents/{setup_intent}/cancel` (HIDE0-001)
* the request parameter `client_secret` of `POST /v1/setup_intents/{setup_intent}/confirm` (HIDE0-004)
* the request parameter `confirm` of `POST /v1/setup_intents/{setup_intent}/confirm` (HIDE0-005)
* the request parameter `currency` of `POST /v1/setup_intents/{setup_intent}/confirm` (HIDE0-006)
* the request parameter `customer` of `POST /v1/setup_intents/{setup_intent}/confirm` (HIDE0-007)
* the request parameter `description` of `POST /v1/setup_intents/{setup_intent}/confirm` (HIDE0-008)
* the request parameter `metadata` of `POST /v1/setup_intents/{setup_intent}/confirm` (HIDE0-009)
* the request parameter `payment_method_data[card]` of `POST /v1/setup_intents/{setup_intent}/confirm` (HIDE0-010)
* the value `card` of `payment_method_data[type]` on `POST /v1/setup_intents/{setup_intent}/confirm` (HIDE0-011)
* the request parameter `receipt_email` of `POST /v1/setup_intents/{setup_intent}/confirm` (HIDE0-012)
* the request parameter `setup_future_usage` of `POST /v1/setup_intents/{setup_intent}/confirm` (HIDE0-013)
* the request parameter `client_secret` of `POST /v1/setup_intents` (HIDE0-029)
* the request parameter `currency` of `POST /v1/setup_intents` (HIDE0-030)
* the request parameter `payment_method_data[card]` of `POST /v1/setup_intents` (HIDE0-031)
* the value `card` of `payment_method_data[type]` on `POST /v1/setup_intents` (HIDE0-032)
* the request parameter `receipt_email` of `POST /v1/setup_intents` (HIDE0-033)
* the request parameter `setup_future_usage` of `POST /v1/setup_intents` (HIDE0-034)
* the request parameter `client_secret` of `POST /v1/setup_intents/{setup_intent}` (HIDE0-082)
* the request parameter `confirm` of `POST /v1/setup_intents/{setup_intent}` (HIDE0-083)
* the request parameter `currency` of `POST /v1/setup_intents/{setup_intent}` (HIDE0-084)
* the request parameter `payment_method_data[card]` of `POST /v1/setup_intents/{setup_intent}` (HIDE0-085)
* the value `card` of `payment_method_data[type]` on `POST /v1/setup_intents/{setup_intent}` (HIDE0-086)
* the request parameter `receipt_email` of `POST /v1/setup_intents/{setup_intent}` (HIDE0-087)
* the request parameter `return_url` of `POST /v1/setup_intents/{setup_intent}` (HIDE0-088)
* the request parameter `setup_future_usage` of `POST /v1/setup_intents/{setup_intent}` (HIDE0-089)