---
title: "Create Payment with Card Details"
method: POST
path: "/payments/direct"
tags: ["Payments"]
---

# Create Payment with Card Details

`POST /payments/direct`

Charges a buyer for a plan 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.) Collection runs in the background: the response is the payment as created, not its outcome — poll Retrieve status for how far it has got and what the buyer must still do, such as 3D Secure.

## Headers

- `Idempotency-Key` string

## Request body

- object
  - `account_id` string, required — The account to charge for, prefixed `biz_`.
  - `auto_capture_after_minutes` integer, nullable — Minutes after authorization at which Whop captures the hold automatically unless it has been voided. Requires `capture: false`. Between 5 and 5760 (4 days).
  - `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.
  - `capture` boolean, nullable — Whether to capture the payment immediately. Defaults to true. Pass false to place an authorization hold that must be captured in full within five days via the capture endpoint, or automatically after `auto_capture_after_minutes`.
  - `member_id` string, nullable — The member to charge, prefixed `mber_`. When omitted the buyer is resolved from `billing_details.email`.
  - `metadata` object, nullable — Custom metadata to attach to the payment.
  - `off_session` boolean, nullable — Whether the charge is merchant-initiated, with the buyer not present. Defaults to false. When true, `payment_method.card.network_transaction_id` is required: a merchant-initiated charge on a card Whop has not charged before carries the id of the card's prior customer-initiated transaction. No 3D Secure step is offered: an issuer that requires the buyer to authenticate declines the charge, and the payment fails with that reason so the card can be charged again with the buyer present. A declined card is not saved.
  - `payment_method` object, required — The payment method to charge, 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 charge. 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.
  - `plan` object — Find or create a plan for this payment. Mutually exclusive with `plan_id` and `line_items`. Creating a plan requires plan:create; creating or updating a product requires the corresponding product permission.
    - `application_fee_amount` number, nullable — Application fee collected by the platform in the plan currency (5.00 means $5.00 for USD). Must be positive and below the initial price for one-time plans or renewal price for recurring plans. Paid to the parent account alongside other processing fees; collection is capped to remaining proceeds. Applies to subsequent payments on recurring plans. Only valid for connected accounts with a parent account.
    - `billing_period` integer, nullable — Recurring billing interval in days.
    - `currency` 'usd' | 'sgd' | 'inr' | 'aud' | 'brl' | 'cad' | 'dkk' | 'eur' | 'nok' | 'gbp' | 'sek' | 'chf' | 'hkd' | 'huf' | 'jpy' | 'mxn' | 'myr' | 'pln' | 'czk' | 'nzd' | 'aed' | 'eth' | 'ape' | 'cop' | 'ron' | 'thb' | 'bgn' | 'idr' | 'dop' | 'php' | 'try' | 'krw' | 'twd' | 'vnd' | 'pkr' | 'clp' | 'uyu' | 'ars' | 'zar' | 'dzd' | 'tnd' | 'mad' | 'kes' | 'kwd' | 'jod' | 'all' | 'xcd' | 'amd' | 'bsd' | 'bhd' | 'bob' | 'bam' | 'khr' | 'crc' | 'xof' | 'egp' | 'etb' | 'gmd' | 'ghs' | 'gtq' | 'gyd' | 'ils' | 'jmd' | 'mop' | 'mga' | 'mur' | 'mdl' | 'mnt' | 'nad' | 'ngn' | 'mkd' | 'omr' | 'pyg' | 'pen' | 'qar' | 'rwf' | 'sar' | 'rsd' | 'lkr' | 'tzs' | 'ttd' | 'uzs' | 'rub' | 'btc' | 'cny' | 'usdt' | 'kzt' | 'awg' | 'whop_usd' | 'xau', required — Currency code for the plan prices.
    - `description` string, nullable — Plan description.
    - `expiration_days` integer, nullable — Days until access expires.
    - `force_create_new_plan` boolean, nullable — Create a new plan instead of reusing a matching plan.
    - `initial_price` number, nullable — Additional amount charged on the first purchase, in the plan currency. For recurring plans without a trial, the first charge includes this amount plus renewal_price.
    - `internal_notes` string, nullable — Internal notes for the account.
    - `plan_type` 'null' | 'renewal' | 'one_time', nullable — Billing model for the plan.
    - `product` object, nullable — Find or create a product by external identifier. Mutually exclusive with product_id.
      - `collect_shipping_address` boolean, nullable — Whether to collect a shipping address at checkout.
      - `custom_statement_descriptor` string, nullable — Custom card statement descriptor for the product, starting with WHOP*.
      - `description` string, nullable — Product description.
      - `external_identifier` string, required — Your unique identifier for the product.
      - `global_affiliate_percentage` number, nullable — Percentage of revenue paid to global affiliates.
      - `global_affiliate_status` 'null' | 'enabled' | 'disabled', nullable — Global affiliate program status.
      - `headline` string, nullable — Product headline.
      - `product_tax_code_id` string, nullable — Product tax code identifier.
      - `redirect_purchase_url` string, nullable — Where to redirect the buyer after purchase.
      - `route` string, nullable — Product route.
      - `title` string, required — Product title.
      - `visibility` 'visible' | 'hidden' | 'archived' | 'quick_link' — Product visibility. Defaults to hidden.
    - `product_id` string, nullable — Existing product ID belonging to the account, prefixed `prod_`. Mutually exclusive with `product`.
    - `renewal_price` number, nullable — Recurring price in the plan currency.
    - `title` string, nullable — Plan title.
    - `trial_period_days` integer, nullable — Free trial days before renewal.
    - `visibility` 'null' | 'visible' | 'hidden' | 'archived' | 'quick_link', nullable — Whether the plan is visible to customers.
  - `plan_id` string — The plan to charge for, prefixed `plan_`. It must belong to the account. Mutually exclusive with `plan`.
  - `promo_code_id` string, nullable — An active promo code to apply, prefixed `promo_`. It must belong to the account and be valid for the plan.
  - `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.
  - `setup_future_usage` 'off_session' | 'on_session', nullable — Attests that the buyer was told the card will be saved for later charges. `off_session` for merchant-initiated charges, `on_session` for buyer-present ones.
  - `statement_descriptor` string, nullable — Overrides the text on the buyer's card statement for this payment only. Must start with `WHOP*`, be 5-22 characters, contain at least one letter, and use only Latin letters, numbers, spaces, underscores, hyphens, or asterisks.

## Response `201`

payment created from card details

- Payment
  - `account_id` string, nullable, required — The account that received the payment, prefixed `biz_`.
  - `amount_after_fees` Money, required
    - `amount` string, required — The amount in major units, as an exact decimal string — `"10.00"` is ten dollars. A string so no float rounds it in transit.
    - `currency` string, required — Three-letter ISO 4217 currency code, lowercase.
    - `decimals` integer, required — How many decimal places the amount CARRIES — the precision the charge itself runs at.
    - `display_decimals` integer, required — How many decimal places to SHOW. Usually equal to `decimals`, and deliberately not always: COP is charged in centavos but written in whole pesos, so it is `2` and `0`. Format the number in your own locale using this.
  - `auto_refunded` boolean, required — True when Whop refunded the payment automatically, for example on a dispute alert.
  - `billing_address` PaymentAddress, required
    - `city` string, nullable, required — The city.
    - `country` string, nullable, required — The ISO 3166-1 alpha-2 country code.
    - `line1` string, nullable, required — The first street address line.
    - `line2` string, nullable, required — The second street address line.
    - `name` string, nullable, required — The name on the address.
    - `postal_code` string, nullable, required — The postal or ZIP code.
    - `state` string, nullable, required — The state, province or region.
  - `billing_reason` 'subscription_create' | 'subscription_cycle' | 'subscription_update' | 'one_time' | 'manual' | 'subscription', required — The reason why a specific payment was billed
  - `checkout_configuration_id` string, nullable, required — The checkout configuration the buyer paid through, prefixed `ch_`, or null.
  - `client_secret` string, nullable, required — The credential a buyer's surface presents to poll this payment and set its return URL. Only on payments created from a confirmation token, and always null in list responses — retrieve the payment for it.
  - `created_at` string, required — When the payment was created, as an ISO 8601 timestamp.
  - `currency` 'usd' | 'sgd' | 'inr' | 'aud' | 'brl' | 'cad' | 'dkk' | 'eur' | 'nok' | 'gbp' | 'sek' | 'chf' | 'hkd' | 'huf' | 'jpy' | 'mxn' | 'myr' | 'pln' | 'czk' | 'nzd' | 'aed' | 'eth' | 'ape' | 'cop' | 'ron' | 'thb' | 'bgn' | 'idr' | 'dop' | 'php' | 'try' | 'krw' | 'twd' | 'vnd' | 'pkr' | 'clp' | 'uyu' | 'ars' | 'zar' | 'dzd' | 'tnd' | 'mad' | 'kes' | 'kwd' | 'jod' | 'all' | 'xcd' | 'amd' | 'bsd' | 'bhd' | 'bob' | 'bam' | 'khr' | 'crc' | 'xof' | 'egp' | 'etb' | 'gmd' | 'ghs' | 'gtq' | 'gyd' | 'ils' | 'jmd' | 'mop' | 'mga' | 'mur' | 'mdl' | 'mnt' | 'nad' | 'ngn' | 'mkd' | 'omr' | 'pyg' | 'pen' | 'qar' | 'rwf' | 'sar' | 'rsd' | 'lkr' | 'tzs' | 'ttd' | 'uzs' | 'rub' | 'btc' | 'cny' | 'usdt' | 'kzt' | 'awg' | 'whop_usd' | 'xau', required — The available currencies on the platform
  - `customer_email` string, nullable, required — The buyer's email address. Null without `member:email:read` on the account or when the buyer has no assigned email.
  - `customer_phone` string, nullable, required — The phone number the buyer gave at checkout, when one was collected.
  - `decline_code` 'insufficient_funds' | 'lost_card' | 'stolen_card' | 'expired_card' | 'suspected_fraud' | 'invalid_card_number' | 'invalid_cvc' | 'invalid_cvc_or_expiration' | 'incorrect_pin' | 'authentication_required' | 'card_not_supported' | 'currency_not_supported' | 'duplicate_transaction' | 'generic_decline' | 'invalid_account' | 'invalid_amount' | 'processing_error' | 'restricted_card' | 'card_velocity_exceeded' | 'contact_issuer' | 'bank_declined' | 'regulatory_blocked' | 'transaction_not_permitted' | 'transaction_stopped' | 'card_type_not_supported' | 'issuer_not_found' | 'closed_account' | 'issuer_unavailable' | 'invalid_zip' | 'invalid_expiry_month' | 'invalid_expiry_year' | 'invalid_expiry' | 'invalid_transaction' | 'cannot_authorize' | 'pin_required' | 'pin_try_exceeded' | 'provider_declined' | 'high_risk' | 'test_mode_decline' | 'merchant_blacklist' | 'reenter_transaction' | 'invalid_pin' | 'pin_required_as' | 'withdrawal_count_limit_exceeded' | 'invalid_country' | 'issuer_error' | 'invalid_card_holder_name' | 'no_accounts' | 'transaction_cancelled' | 'three_d_secure_success' | 'three_d_secure_canceled' | 'three_d_secure_invalid_card_number' | 'three_d_secure_generic_error' | 'three_d_secure_timeout' | 'three_d_secure_failed' | 'three_d_secure_card_not_enrolled' | 'three_d_secure_fraud' | 'three_d_secure_too_many_attempts' | 'three_d_secure_rejected_by_bank' | 'three_d_secure_reported_lost_or_stolen' | 'blocked_by_cardholder' | 'test_mode_test_card' | 'try_again_later' | 'transaction_not_allowed' | 'bank_insufficient_funds' | 'bank_account_not_found' | 'bank_account_closed' | 'bank_account_frozen' | 'bank_invalid_routing_number' | 'bank_non_transaction_account' | 'bank_authorization_revoked' | 'bank_payment_stopped' | 'bank_not_authorized' | 'bank_account_holder_deceased' | 'bank_duplicate' | 'bank_amount_error' | 'bank_regulatory_blocked' | 'bank_details_invalid' | 'bank_processing_error' | 'bank_generic_decline' | 'sepa_invalid_iban' | 'sepa_no_mandate' | 'sepa_mandate_data_invalid' | 'sepa_disputed' | 'sepa_refused_by_customer' | 'sepa_generic_decline', required — The reason a payment was declined.
  - `dispute_alerted_at` string, nullable, required — When an issuer warned that this payment will be disputed, or null.
  - `failure_message` string, nullable, required — Why the most recent attempt failed, in plain words, or null.
  - `financing_installments_count` number, nullable, required — For installment methods, how many payments the charge splits into.
  - `holds` PaymentHold[], required
    - `amount` Money, required
      - `amount` string, required — The amount in major units, as an exact decimal string — `"10.00"` is ten dollars. A string so no float rounds it in transit.
      - `currency` string, required — Three-letter ISO 4217 currency code, lowercase.
      - `decimals` integer, required — How many decimal places the amount CARRIES — the precision the charge itself runs at.
      - `display_decimals` integer, required — How many decimal places to SHOW. Usually equal to `decimals`, and deliberately not always: COP is charged in centavos but written in whole pesos, so it is `2` and `0`. Format the number in your own locale using this.
    - `percentage` number, nullable, required — The reserve percentage recorded when the hold was created, for example 3.5 for 3.5%. Null for other hold types or when no percentage was recorded.
    - `release_at` string, nullable, required — When the held funds are scheduled to become available, as an ISO 8601 timestamp. Never earlier than the payment's settlement date. Null when release depends on an event, such as shipment resolution, rather than a date.
    - `type` 'reserve' | 'bnpl' | 'sequra' | 'fraud_hold' | 'preshipment_hold', required — The reason funds are held: `reserve`, `bnpl`, `sequra`, `fraud_hold`, or `preshipment_hold`.
  - `id` string, required — Payment ID, prefixed `pay_`.
  - `last_payment_attempt_at` string, nullable, required — When the most recent charge attempt ran, or null.
  - `line_items` ReceiptLineItem[], required
    - `id` string, nullable, required — Line item ID, prefixed `li_`. Null when the payment predates item snapshots and the item is read from the payment's plan.
    - `label` string, nullable, required — The item's name as shown at checkout — the product title, else the plan title.
    - `plan_id` string, nullable, required — The plan bought, prefixed `plan_`. Null when the plan has since been deleted.
    - `plan_title` string, nullable, required — The plan's current title, or `null` when the plan has been deleted or has no title.
    - `product_id` string, nullable, required — The product the plan belongs to, prefixed `prod_`. On a payment that predates item snapshots this falls back to the plan's product, so it can be set where the parent's own `product_id` is null. Null for a plan with no product.
    - `product_title` string, nullable, required — The product's current title, or `null` when the item has no product.
    - `quantity` number, required — How many units were bought.
    - `subtotal` Money, required
      - `amount` string, required — The amount in major units, as an exact decimal string — `"10.00"` is ten dollars. A string so no float rounds it in transit.
      - `currency` string, required — Three-letter ISO 4217 currency code, lowercase.
      - `decimals` integer, required — How many decimal places the amount CARRIES — the precision the charge itself runs at.
      - `display_decimals` integer, required — How many decimal places to SHOW. Usually equal to `decimals`, and deliberately not always: COP is charged in centavos but written in whole pesos, so it is `2` and `0`. Format the number in your own locale using this.
  - `member_id` string, nullable, required — The buyer's member record on the account, prefixed `mber_`. Null without the member:basic:read permission.
  - `membership_id` string, nullable, required — The membership this payment is billed against, prefixed `mem_`. Null for one-off purchases or without the member:basic:read permission.
  - `metadata` object, nullable, required — Your own key-value data attached when the payment was created.
  - `needs_tracking` boolean, nullable, required — True when funds are held until the order ships and no tracking number has been added yet. Null without the shipment:basic:read permission.
  - `next_payment_attempt_at` string, nullable, required — When the next automatic retry is scheduled, or null.
  - `paid_at` string, nullable, required — When the money was collected, or null while it has not been.
  - `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 stored payment method that was charged, prefixed `payt_`. Null when the method was not saved.
  - `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' | 'tabby' | '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.
  - `payment_rule_matches` PaymentRuleMatch[], required
    - `action` 'allow' | 'block' | 'review' | 'enforce_3ds', required — What the rule asked for.
    - `id` string, required — Payment rule ID, prefixed `prule_`.
    - `name` string, nullable, required — The rule's name when it matched. Renaming the rule afterwards does not rewrite this.
  - `payments_failed` number, required — How many charge attempts have failed on this payment.
  - `plan_id` string, nullable, required — The plan that was charged, prefixed `plan_`.
  - `presentment_total` Money, required
    - `amount` string, required — The amount in major units, as an exact decimal string — `"10.00"` is ten dollars. A string so no float rounds it in transit.
    - `currency` string, required — Three-letter ISO 4217 currency code, lowercase.
    - `decimals` integer, required — How many decimal places the amount CARRIES — the precision the charge itself runs at.
    - `display_decimals` integer, required — How many decimal places to SHOW. Usually equal to `decimals`, and deliberately not always: COP is charged in centavos but written in whole pesos, so it is `2` and `0`. Format the number in your own locale using this.
  - `product_id` string, nullable, required — The product the plan belongs to, prefixed `prod_`. Null for a plan with no product.
  - `promo_code_id` string, nullable, required — The promo code applied at checkout, prefixed `promo_`, or null.
  - `recovery_url` string, nullable, required — Whop-hosted URL where the buyer can sign in and complete 3D Secure for an off-session charge the bank challenged — a subscription renewal or a saved-card payment. Null when recovery is unavailable, you lack `member:basic:read`, or in list responses. Retrieve the payment for it.
  - `refundable` boolean, required — True when the payment is `paid`, not yet fully refunded, and its processor supports refunds.
  - `refunded_amount` Money, required
    - `amount` string, required — The amount in major units, as an exact decimal string — `"10.00"` is ten dollars. A string so no float rounds it in transit.
    - `currency` string, required — Three-letter ISO 4217 currency code, lowercase.
    - `decimals` integer, required — How many decimal places the amount CARRIES — the precision the charge itself runs at.
    - `display_decimals` integer, required — How many decimal places to SHOW. Usually equal to `decimals`, and deliberately not always: COP is charged in centavos but written in whole pesos, so it is `2` and `0`. Format the number in your own locale using this.
  - `refunded_at` string, nullable, required — When the payment was refunded, or null.
  - `retryable` boolean, required — True when the payment is `open` and Whop can attempt the charge again — see `POST /payments/{id}/retry`.
  - `risk_score` number, nullable, required — Whop's published risk index from 0 (lowest) to 100 (highest), including enforced decision floors. This is not a fraud probability. Null when no score is available.
  - `risk_signals` object, nullable, required — Deprecated. Risk score explanations are no longer provided; always null. DEPRECATED: Risk score explanations are no longer provided. Always null.
  - `settlement_time_at` string, nullable, required — When the portion not listed in `holds` posts to the account's available balance, at midnight UTC. The `financial_activity.funds_available` webhook's `posted_at` carries the same value when the settlement that clears it posts. Null until the payment is paid, and always null in list responses — retrieve the payment for it.
  - `shipment_id` string, nullable, required — The shipment fulfilling this payment, prefixed `ship_`. Null when nothing ships or without the shipment:basic:read permission.
  - `shipping_address` PaymentAddress, required
    - `city` string, nullable, required — The city.
    - `country` string, nullable, required — The ISO 3166-1 alpha-2 country code.
    - `line1` string, nullable, required — The first street address line.
    - `line2` string, nullable, required — The second street address line.
    - `name` string, nullable, required — The name on the address.
    - `postal_code` string, nullable, required — The postal or ZIP code.
    - `state` string, nullable, required — The state, province or region.
  - `status` 'draft' | 'open' | 'authorized' | 'paid' | 'pending' | 'uncollectible' | 'unresolved' | 'void', required — The status of a receipt
  - `substatus` 'succeeded' | 'requires_capture' | 'pending' | 'failed' | 'blocked' | 'past_due' | 'canceled' | 'price_too_low' | 'uncollectible' | 'refunded' | 'auto_refunded' | 'partially_refunded' | 'dispute_warning' | 'dispute_needs_response' | 'dispute_warning_needs_response' | 'resolution_needs_response' | 'dispute_under_review' | 'dispute_warning_under_review' | 'resolution_under_review' | 'dispute_won' | 'dispute_warning_closed' | 'resolution_won' | 'dispute_lost' | 'dispute_closed' | 'resolution_lost' | 'drafted' | 'incomplete' | 'unresolved' | 'open_dispute' | 'open_resolution', required — The friendly status of a payment. This is a derived status that provides a human-readable summary of the payment state, combining the underlying status and substatus fields.
  - `subtotal` Money, required
    - `amount` string, required — The amount in major units, as an exact decimal string — `"10.00"` is ten dollars. A string so no float rounds it in transit.
    - `currency` string, required — Three-letter ISO 4217 currency code, lowercase.
    - `decimals` integer, required — How many decimal places the amount CARRIES — the precision the charge itself runs at.
    - `display_decimals` integer, required — How many decimal places to SHOW. Usually equal to `decimals`, and deliberately not always: COP is charged in centavos but written in whole pesos, so it is `2` and `0`. Format the number in your own locale using this.
  - `tax_amount` Money, required
    - `amount` string, required — The amount in major units, as an exact decimal string — `"10.00"` is ten dollars. A string so no float rounds it in transit.
    - `currency` string, required — Three-letter ISO 4217 currency code, lowercase.
    - `decimals` integer, required — How many decimal places the amount CARRIES — the precision the charge itself runs at.
    - `display_decimals` integer, required — How many decimal places to SHOW. Usually equal to `decimals`, and deliberately not always: COP is charged in centavos but written in whole pesos, so it is `2` and `0`. Format the number in your own locale using this.
  - `tax_behavior` 'exclusive' | 'inclusive' | 'unspecified' | 'unable_to_collect', required — The type of tax inclusivity applied to the receipt, for determining whether the tax is included in the final price, or paid on top.
  - `tax_refunded_amount` Money, required
    - `amount` string, required — The amount in major units, as an exact decimal string — `"10.00"` is ten dollars. A string so no float rounds it in transit.
    - `currency` string, required — Three-letter ISO 4217 currency code, lowercase.
    - `decimals` integer, required — How many decimal places the amount CARRIES — the precision the charge itself runs at.
    - `display_decimals` integer, required — How many decimal places to SHOW. Usually equal to `decimals`, and deliberately not always: COP is charged in centavos but written in whole pesos, so it is `2` and `0`. Format the number in your own locale using this.
  - `three_ds_verified` boolean, required — True when the buyer completed 3D Secure for this payment.
  - `total` Money, required
    - `amount` string, required — The amount in major units, as an exact decimal string — `"10.00"` is ten dollars. A string so no float rounds it in transit.
    - `currency` string, required — Three-letter ISO 4217 currency code, lowercase.
    - `decimals` integer, required — How many decimal places the amount CARRIES — the precision the charge itself runs at.
    - `display_decimals` integer, required — How many decimal places to SHOW. Usually equal to `decimals`, and deliberately not always: COP is charged in centavos but written in whole pesos, so it is `2` and `0`. Format the number in your own locale using this.
  - `updated_at` string, required — When the payment last changed, as an ISO 8601 timestamp.
  - `usd_total` Money, required
    - `amount` string, required — The amount in major units, as an exact decimal string — `"10.00"` is ten dollars. A string so no float rounds it in transit.
    - `currency` string, required — Three-letter ISO 4217 currency code, lowercase.
    - `decimals` integer, required — How many decimal places the amount CARRIES — the precision the charge itself runs at.
    - `display_decimals` integer, required — How many decimal places to SHOW. Usually equal to `decimals`, and deliberately not always: COP is charged in centavos but written in whole pesos, so it is `2` and `0`. Format the number in your own locale using this.
  - `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.
  - `verification_checks` PaymentVerificationChecks, required
    - `address_line1` string, nullable, required — The Address Verification Service (AVS) result for the billing street address.
    - `authorization_code` string, nullable, required — The card issuer's authorization code for this charge, or null when the processor did not return one.
    - `card_holder_name` string, nullable, required — Whether the cardholder name matched the issuer's records.
    - `card_security_code` string, nullable, required — The Card Verification Value (CVV/CVC) result.
    - `zip_code` string, nullable, required — The Address Verification Service (AVS) result for the billing postal code.
  - `voidable` boolean, required — True when the payment can be voided or canceled. The request is rejected if the payment is no longer eligible — see `POST /payments/{id}/void`.

## Other responses

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

## Changes

> 71 revisions in range; 1 not diffed.

- **2026-09-24** `7fcefabddb0a` — 1 warning
  - added the new `tabby` enum value to the `payment_method_type/oneOf[#/components/schemas/PaymentMethodTypes]/` response property for the response status `201`
- **2026-09-23** `140d015b9966` — 1 info
  - endpoint added

[Change history](https://skmtc.dev/whop/apis/whop-api/changes/payments/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/c1dceb26e505?raw)
