---
title: "Save Card Details"
method: POST
path: "/setup_intents/direct"
tags: ["Setup Intents"]
---

# Save Card Details

`POST /setup_intents/direct`

Saves a card for later charges from card details the caller holds itself, for integrators whose own systems are PCI compliant. Card details are accepted only on the vault host, where the card is tokenized before it reaches Whop; the official SDKs route this operation there, and raw card details sent to the regular host are refused. (Whop's own clients, which tokenize with the Basis Theory SDK, send the resulting token intent id to the regular host.) The setup runs in the background: poll Retrieve setup status for its outcome and for anything the buyer must still do, such as 3D Secure. Once it succeeds, the saved payment method arrives on the `setup_intent.succeeded` webhook and in List payment methods for the member.

## Headers

- `Idempotency-Key` string

## Request body

- object
  - `account_id` string, required — The account the card is saved for, prefixed `biz_`.
  - `billing_details` object, required — The buyer's billing details.
    - `address` object, required — The billing address.
      - `city` string — City.
      - `country` string, required — Two-letter ISO 3166-1 country code.
      - `line1` string — Street address, first line.
      - `line2` string, nullable — Street address, second line.
      - `postal_code` string, required — Postal code.
      - `state` string, nullable — State, province or region.
    - `email` string, required — The buyer's email. Resolves or creates the user the operation is for.
    - `name` string, required — The name on the card.
    - `phone` string, nullable — The buyer's phone number in E.164 format.
  - `currency` string, nullable — The currency the card will be charged in, as a three-letter code. Defaults to usd.
  - `member_id` string, nullable — The member the card belongs to, prefixed `mber_`. When omitted the buyer is resolved from `billing_details.email`.
  - `metadata` object, nullable — Custom metadata to attach to the setup.
  - `payment_method` object, required — The payment method to save, as the raw details the caller holds. Raw details are accepted only on the vault host, where Whop's vault tokenizes them in transit; the official SDKs route this operation there. Whop's own clients, which tokenize with the Basis Theory SDK, send the resulting token intent id to the regular host.
    - `card` object — The card to save. Present when `type` is `card`.
      - `details` object, required — The card's raw fields. Sent to the vault host and tokenized before it reaches Whop; Whop's servers never receive the number.
        - `cvc` string — The card security code.
        - `exp_month` integer, required — The expiry month.
        - `exp_year` integer, required — The four-digit expiry year.
        - `number` string, required — The card number, digits only.
      - `network_transaction_id` string, nullable — The network transaction id of the card's most recent customer-initiated transaction on another processor, when the caller brings a card it has charged before. Required for an `off_session` charge; on a setup it is kept with the saved card for its later charges. Up to 64 characters.
    - `type` 'card', required — The kind of payment method; the member named after it carries the credential.
  - `return_url` string, nullable — Where the buyer continues after completing an off-site step such as 3D Secure. An absolute https URL without credentials, at most 2,048 characters.

## Response `201`

setup started from card details

- SetupIntent
  - `account_id` string, nullable, required — The account the payment method is saved for, prefixed `biz_`.
  - `checkout_configuration_id` string, nullable, required — The checkout configuration this setup was created through, prefixed `ch_`. Null for a setup created through this API rather than a hosted checkout.
  - `client_secret` string, nullable, required — The credential a buyer's surface presents to poll this setup and set its return URL — hand it to the elements' `handleNextAction`. Only on setups created through this API, and always null in list responses — retrieve the setup intent for it.
  - `created_at` string, required — When the setup intent was created, as an ISO 8601 timestamp.
  - `id` string, required — Setup intent ID, prefixed `sint_`.
  - `last_setup_error` SetupLastSetupError, required
    - `code` string, nullable, required — A machine-readable classification of the failure, e.g. `enrollment_declined`. Absent when the buyer simply abandoned the setup.
    - `message` string, nullable, required — A human-readable explanation of the failure.
  - `member_id` string, nullable, required — The buyer's member record on the account, prefixed `mber_`. Null without the member:basic:read permission, unless the caller is the buyer.
  - `metadata` object, nullable, required — Your own key-value data attached when the setup intent was created.
  - `payment_instrument` PaymentInstrument, required
    - `card` PaymentInstrumentCard, required
      - `brand` string, nullable, required — The network identifier (`visa`, `amex`, …), matching `card.networks` entries and saved card payment methods. Null when the vault did not record the network.
      - `exp_month` number, nullable, required — The card's expiry month, 1 to 12. Null when the vault did not record it.
      - `exp_year` number, nullable, required — The card's four-digit expiry year. Null when the vault did not record it.
      - `issuer_identification_number` string, nullable, required — The issuer identification number, also called the BIN: the card's leading six or eight digits, which identify the issuing bank. Null when the processor did not report it.
      - `last4` string, nullable, required — The card's last four digits, when captured.
    - `display_name` string, required — Buyer-facing instrument name — "Visa •••• 4242" when the card surfaced, else the method's own name ("Klarna").
    - `icons` PaymentMethodIcons, required
      - `card` PaymentMethodIconVariants, required
        - `dark` PaymentMethodIconFiles, required
          - `png_1x` string, required — Raster fallback at the shape's native size.
          - `png_2x` string, required — Raster fallback at double density.
          - `png_4x` string, required — Raster fallback at quadruple density.
          - `svg` string, required — The vector file. Prefer this everywhere SVG renders.
        - `light` PaymentMethodIconFiles, required
          - `png_1x` string, required — Raster fallback at the shape's native size.
          - `png_2x` string, required — Raster fallback at double density.
          - `png_4x` string, required — Raster fallback at quadruple density.
          - `svg` string, required — The vector file. Prefer this everywhere SVG renders.
      - `square` PaymentMethodIconVariants, required
        - `dark` PaymentMethodIconFiles, required
          - `png_1x` string, required — Raster fallback at the shape's native size.
          - `png_2x` string, required — Raster fallback at double density.
          - `png_4x` string, required — Raster fallback at quadruple density.
          - `svg` string, required — The vector file. Prefer this everywhere SVG renders.
        - `light` PaymentMethodIconFiles, required
          - `png_1x` string, required — Raster fallback at the shape's native size.
          - `png_2x` string, required — Raster fallback at double density.
          - `png_4x` string, required — Raster fallback at quadruple density.
          - `svg` string, required — The vector file. Prefer this everywhere SVG renders.
    - `installment_count` number, nullable, required — Installment methods only: how many payments the charge splits into. Data, not copy — compose and translate the label client-side.
    - `payment_method_type` string, required — The payment method type identifier, e.g. `card`, `klarna`, `apple_pay`.
  - `payment_method_id` string, nullable, required — The saved payment method, prefixed `payt_`, ready to charge with Create Payment. Null until the setup has `succeeded`.
  - `payment_method_type` 'acss_debit' | 'addi' | 'affirm' | 'afterpay_clearpay' | 'alipay' | 'alma' | 'amazon_pay' | 'apple' | 'apple_pay' | 'au_bank_transfer' | 'au_becs_debit' | 'bacs_debit' | 'bancolombia' | 'bancontact' | 'bank_wire' | 'billie' | 'blik' | 'boleto' | 'bre_b' | 'ca_bank_transfer' | 'capchase_pay' | 'card' | 'card_installments_three' | 'card_installments_six' | 'card_installments_twelve' | 'cashapp' | 'claritypay' | 'coinbase' | 'crypto' | 'custom' | 'customer_balance' | 'demo_pay' | 'efecty' | 'eps' | 'eu_bank_transfer' | 'fpx' | 'flex_pay' | 'gb_bank_transfer' | 'gcash' | 'giropay' | 'google_pay' | 'gopay' | 'grabpay' | 'id_bank_transfer' | 'ideal' | 'interac' | 'kakao_pay' | 'klarna' | 'klarna_pay_now' | 'konbini' | 'kr_card' | 'kr_market' | 'kriya' | 'kueski' | 'link' | 'mb_way' | 'm_pesa' | 'mercado_pago' | 'mercado_pago_ar' | 'mercado_pago_mx' | 'mobilepay' | 'modo' | 'mondu' | 'multibanco' | 'naver_pay' | 'nequi' | 'netbanking' | 'ng_bank' | 'ng_bank_transfer' | 'ng_card' | 'ng_market' | 'ng_ussd' | 'ng_wallet' | 'nupay' | 'nz_bank_account' | 'oney' | 'oney_3x' | 'oney_4x' | 'opay' | 'oxxo' | 'p24' | 'pago_efectivo' | 'pse' | 'pay_by_bank' | 'payco' | 'paynow' | 'paypal' | 'paypay' | 'payto' | 'pix' | 'platform_balance' | 'promptpay' | 'qris' | 'rapipago' | 'rechnung' | 'revolut_pay' | 'samsung_pay' | 'satispay' | 'scalapay' | 'sencillito' | 'sepa_debit' | 'sequra' | 'servipag' | 'sezzle' | 'shop_pay' | 'shopeepay' | 'sofort' | 'south_korea_market' | 'spei' | 'splitit' | 'sunbit' | 'swish' | 'tamara' | 'touch_n_go' | 'twint' | 'upi' | 'us_bank_account' | 'us_bank_transfer' | 'venmo' | 'verve' | 'vipps' | 'webpay' | 'wechat_pay' | 'yape' | 'zip' | 'coinflow' | 'unknown', required — The different types of payment methods that can be used.
  - `return_url` string, nullable, required — Where the buyer lands after completing an off-site step, or `null` to leave them where they are.
  - `status` 'processing' | 'succeeded' | 'canceled' | 'requires_action', required — How far the setup has got. **A 201 or 200 means we answered, not that the method was saved — always branch on this.** `requires_action` — the buyer has a step outstanding; hand `client_secret` to the elements or poll Retrieve setup status. `processing` — the processor is deciding. `succeeded` — the method is saved, and only this one means saved. `canceled` — abandoned or refused; see `last_setup_error`.
  - `three_ds_verified` boolean, required — True when the buyer completed 3D Secure while saving this payment method.
  - `updated_at` string, required — When the setup intent was last updated, as an ISO 8601 timestamp.
  - `user` UserSummary, required
    - `id` string, required — User ID, prefixed `user_`.
    - `name` string, nullable, required — Display name.
    - `profile_picture` UserProfilePicture, required
      - `url` string, required — Avatar image URL. Always present — a generated placeholder when the user set no picture.
    - `username` string, required — Public username.

## Other responses

- `401` — Unauthorized
- `409` — Conflict

## Changes

> 69 revisions in range; 1 not diffed.

- **2026-09-23** `140d015b9966` — 1 info
  - endpoint added

[Change history](https://skmtc.dev/whop/apis/whop-api/changes/setup_intents/direct/post.md)

---

[API](https://skmtc.dev/whop/apis/whop-api.md) · [All operations](https://skmtc.dev/whop/apis/whop-api/llms.txt) · [OpenAPI document](https://skmtc.dev/whop/apis/whop-api/revisions/140d015b9966?raw)
