> ## Documentation Index
> Fetch the complete documentation index at: https://docs.payra.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Payment methods

> The card or bank account your server can charge, made from a succeeded session. Never the numbers.

Once [Payra Elements](/elements) has collected a card or a bank account and the
[session](/payment-method-sessions) is `succeeded`, your server turns it into a **payment method**: a
`pm_test_…` / `pm_live_…` object that names the instrument as far as you may see it (a card's brand, last four
digits and expiration date; a bank account's last four digits, account type and holder type) and that your server
[charges](/payments). The tokenized details stay inside Payra and never appear in a response.

<Steps>
  <Step title="Get the session id back on your server">
    Your page already has it: `confirmPaymentMethodSession` resolves with `{ paymentMethodSession }`, and your server
    created it.
    Send the `id` to your backend the way you send any form result. Nothing secret travels: the id alone cannot
    collect, charge or read anything.
  </Step>

  <Step title="Create the payment method with your secret key">
    ```bash theme={null}
    curl -X POST https://api-dashboard.payra.com/v1/payment-methods \
      -H "Authorization: Bearer sk_test_..." \
      -H "Idempotency-Key: 4b6f1e2a-8c3d-4f5e-9a1b-2c3d4e5f6a7b" \
      -H "Content-Type: application/json" \
      -d '{ "session": "pms_test_7Hs2kQ9mL1pXv4cR8tWzAbCd", "account_holder_authorization": true }'
    ```

    ```json Response theme={null}
    {
      "object": "payment_method",
      "id": "pm_test_9kQ2mL7Hs1pXv4cR8tWzAbCd",
      "type": "card",
      "usage": "saved",
      "status": "active",
      "customer": "019e...",
      "session": "pms_test_7Hs2kQ9mL1pXv4cR8tWzAbCd",
      "card": { "brand": "visa", "last4": "4242", "exp_month": 12, "exp_year": 2030, "funding": "credit" },
      "us_bank_account": null,
      "billing_details": { "name": "Ada Lovelace", "postal_code": "94110" },
      "livemode": false,
      "expires_at": null,
      "created_at": "2026-09-18T14:00:00.000Z"
    }
    ```

    `type` says which block is set, the other being `null`. A bank account collected without a customer reads:

    ```json theme={null}
    {
      "object": "payment_method",
      "id": "pm_test_2bL7Hs9kQ1pXv4cR8tWzAbCd",
      "type": "us_bank_account",
      "usage": "one_time",
      "status": "active",
      "customer": null,
      "session": "pms_test_4mL1pXv7Hs2kQ9cR8tWzAbCd",
      "card": null,
      "us_bank_account": { "last4": "6789", "account_type": "checking", "account_holder_type": "individual" },
      "billing_details": { "name": "Ada Lovelace", "postal_code": "94110" },
      "livemode": false,
      "expires_at": "2026-09-23T18:34:12.000Z",
      "created_at": "2026-09-23T18:04:12.000Z"
    }
    ```

    Each session creates one payment method. A second call with the same session answers
    `400 payment_method_session_used`, naming the method it already created; a retry with the same
    [`Idempotency-Key`](/idempotency) answers the first response again. Create the method soon after the
    confirm: a session that succeeded more than 30 minutes ago answers `400 payment_method_session_inactive`.
  </Step>

  <Step title="Keep the id">
    Store `pm_…` with your customer or order. Read it back any time with
    [retrieve](/api-reference/payment-methods/retrieve-a-payment-method); the session also carries it as
    `payment_method`.
  </Step>
</Steps>

## Saved or one-time

The session decides, when your server creates it:

| Session              | `usage`    | What happens                                                                                                                                                                                                                                                            | Lifetime                                                                                             |
| -------------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| With a `customer`    | `saved`    | Payra verifies the card with the workspace's processor and saves it on the customer's file, where it also appears in the Payra dashboard. `account_holder_authorization: true` is required: it is your attestation that the cardholder agreed to keep the card on file. | Until removed from the customer's file (`status: detached`).                                         |
| Without a `customer` | `one_time` | Nothing is sent to the processor yet; the tokenized card waits for a charge.                                                                                                                                                                                            | `expires_at`, 30 minutes after the session was confirmed (`status: expired`). Charge it before then. |

Saving a card needs a billing postal code. Elements has no postal code field: collect it on your page and pass
it as `billingDetails.postalCode` when you confirm the session, or the create answers `400 parameter_invalid` on
`billing_details.postal_code`. It must be a US ZIP or a Canadian postal code; a malformed one already fails the
confirm, with `400 parameter_invalid` on `billing_postal_code`.

A bank account carries its own authorization, so `account_holder_authorization` is not used: the account holder
accepted the ACH authorization in Elements, and Payra kept the record. Saved with a customer, the account is verified
with the workspace's ACH processor and kept on file under that standing authorization until the account is removed
from the customer's file, by your team in the Payra dashboard or by the customer in the customer portal (the method
then reads `detached`). Without a customer it can be debited once, within 30
minutes, for exactly the `amount` its session named.

## Lifecycle

| `status`   | Meaning                                                                         |
| ---------- | ------------------------------------------------------------------------------- |
| `active`   | Ready to be charged.                                                            |
| `consumed` | A one-time method that was [charged](/payments), approved or declined.          |
| `expired`  | A one-time method past `expires_at`. Never stored: it is read off `expires_at`. |
| `detached` | A saved method that was removed from the customer's file.                       |

## Errors on create

| Code                                                   | Why                                                                                                                                                                                                        |
| ------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `parameter_invalid` on `session`                       | Unknown session, or one that belongs to another workspace or environment.                                                                                                                                  |
| `payment_method_session_inactive`                      | The session has not been confirmed yet (let Elements confirm it, then retry with a new `Idempotency-Key`), or it was canceled, expired, or succeeded more than 30 minutes ago (collect again).             |
| `payment_method_session_used`                          | The session already created a payment method (the message names it), or another create is still working on it: read the session back, and its `payment_method` names the method once that create finishes. |
| `card_expired` (`card_error`)                          | The collected card's expiry month has passed.                                                                                                                                                              |
| `parameter_invalid` on `account_holder_authorization`  | A card session names a customer and the attestation is missing or `false`.                                                                                                                                 |
| `parameter_invalid` on `customer`                      | The session's customer is no longer available in your workspace.                                                                                                                                           |
| `payment_provider_not_configured`                      | Card payments, or ACH debits, are not set up for the workspace, so the method cannot be saved.                                                                                                             |
| `card_verification_failed` (402, `card_error`)         | The processor refused to verify the card. Collect the card details again with a new session and retry.                                                                                                     |
| `bank_account_verification_failed` (402, `card_error`) | The processor refused to verify the bank account. Collect the account details again with a new session and retry.                                                                                          |

## What a payment method never carries

The tokenized card number and security code, the tokenized routing and account numbers, or any processor
reference. Payment methods belong to the workspace
and environment of the key that created them: a `pm_test_…` read with a live key, or with another workspace's key,
answers `404 resource_missing`.
