---
title: "Create a PaymentMethod"
method: POST
path: "/api/payment_methods/"
tags: ["Payment Methods"]
---

# Create a PaymentMethod

`POST /api/payment_methods/`

A `POST` request to `/payment_methods/` creates a new representation of a customer's payment instrument in Forage's database.

> 📘 **Tokenization vs. Network Validation**
>
> **Tokenization (this endpoint)**: Forage validates card format, BIN support, and merchant configuration. The EBT network is NOT contacted during tokenization. **Card validity can only be confirmed after attempting a balance check or payment with the processor.**
>
> **Network validation**: Occurs later during balance checks or payments when the EBT network validates the card, PIN, and account status.

| Stage | Who validates | When it happens | Example errors |
|-------|---------------|-----------------|----------------|
| Tokenization | Forage | `POST /payment_methods` | invalid PAN, unsupported BIN/state, throttling |
| Processing | EBT network | balance check or payment | card closed, insufficient funds, wrong PIN |

> ⚠️ **BIN Blocking Scope**
>
> Forage blocks known BINs from restricted states (Guam, Virgin Islands) where online EBT is not supported. However, Forage does not block unregistered BINs. An unregistered BIN may pass tokenization but will fail during processing when the EBT network rejects the card.

On success, the API responds with a Forage `PaymentMethod` object. You need to retrieve and store the `ref` value for future requests. For example:
- To get the outcome of a balance inquiry, you need to pass the `ref` as the path param in a request to [Retrieve a `PaymentMethod`](https://docs.joinforage.app/reference/get-payment-method).
- To [Create a `Payment`](https://docs.joinforage.app/reference/create-a-payment), you need to pass the `ref` as the `payment_method` request body param.

### When to use the `Merchant-Account` Header

The `Merchant-Account` Header requirements vary by payment method type:

- **For EBT payment methods**: The `Merchant-Account` header is **optional**
- **For HSA/FSA payment methods**: The `Merchant-Account` header is **required**
- **For credit/debit payment methods**: The `Merchant-Account` header is **required**

The `Merchant-Account` header is required for all payment methods except EBT due to technical requirements for routing and payout processing.



**EBT PaymentMethods are tenant-scoped.** An EBT `PaymentMethod` created under one merchant account can be used by other merchant accounts within the same tenant. The `Merchant-Account` header does not restrict EBT `PaymentMethod` usability across merchant accounts within the same tenant.

When `Merchant-Account` is passed, the created `PaymentMethod` is associated with that specific merchant account for routing and reporting purposes. For EBT payment methods, the `PaymentMethod` remains usable across all merchant accounts within the same tenant.

> 📘 SDK Behavior
>
> Forage JS automatically includes the `Merchant-Account` header from initialization when creating `PaymentMethod`s. There is currently no option to omit this header during `PaymentMethod` creation.

> 📘 Use `customer_id` When Creating PaymentMethods
>
> Pass `customer_id` in the request to Create a `PaymentMethod`. `customer_id` helps Forage's servers more quickly identify and associate the correct customer with the `PaymentMethod`. While `customer_id` is not technically a required parameter, if you omit it then the request to create the `PaymentMethod` could take longer to process. **It is strongly recommended to pass `customer_id`.**
>
> Additionally, passing `customer_id` enables Forage to throttle card additions per customer, helping prevent abuse and fraud.
>
> Each customer should only have one unique `customer_id`. For example, if you create both a `PaymentMethod` and a `Payment` for the same customer, then the `customer_id` should be the same in both requests to ensure continuity of stored payment methods.

> 📘 State Validation
>
> To check which states and BINs Forage supports, use the [Retrieve state card details](https://docs.joinforage.app/reference/retrieve-state-card-details) endpoint. This is useful for customers concerned with state waivers or validating card eligibility before tokenization.

See these guides for more information:

- [How Custom integrations work](https://docs.joinforage.app/docs/custom#how-it-works)
- [Custom Quickstart](https://docs.joinforage.app/docs/custom-quickstart)

## Headers

- `Authorization` string, required
- `Merchant-Account` string, required
- `API-Version` string

## Request body

- object — An object that represents a customer's payment instrument.
  - `type` 'credit' | 'debit' | 'prepaid' | 'ebt', required — The card type. One of: - `credit` - `debit` - `prepaid` - `ebt` ⚠️ The `type` value can only be `credit`, `debit`, or `prepaid` in a [Fully Hosted](https://docs.joinforage.app/docs/fully-hosted) or [HSA/FSA](https://docs.joinforage.app/docs/enable-hsa-fsa-payments) integration.
  - `reusable` boolean, required — Whether the `PaymentMethod` can be reused. If `false`, then the `PaymentMethod` can only be used for a single transaction.
  - `customer_id` string — **⚠️ If you’re integrating Forage with a POS Terminal, then do not use this param. It is only supported for online transactions.** A unique identifier for the end customer making the payment. Forage automatically adds the `customer_id` to the Session's corresponding `Order` and `OrderPayments`. This field helps Forage's servers more quickly identify the customer associated with the request. While `customer_id` is not technically required, if you omit it then requests could take longer to process. **It is strongly recommended to pass customer_id.** If you're providing your internal customer ID, then we recommend that you hash the value before sending it on the payload. Each customer should only have one unique `customer_id`. For example, if you create both a `PaymentMethod` and a Forage `Session` (Fully Hosted or Custom) or `Payment` (SDK) for the same customer, then the `customer_id` should be the same in both requests to ensure continuity of stored payment methods.
  - `card` union
    - EBTCard — An object that details information about the EBT Card.
      - `number` string, required — The EBT Card number minus any separators.
    - StripeCard — If Stripe is the credit/debit [PSP](https://docs.joinforage.app/docs/ebt-online-101#creditdebit-payment-service-provider-psp), then this object details information about the non-EBT Card.
      - `brand` 'amex' | 'discover' | 'mastercard' | 'visa', required — The card brand. One of: - `amex` - `discover` - `mastercard` - `visa`
      - `exp_month` number, required — The expiration month as listed on the card, without any preceding `0` (e.g. `4` instead of `04`).
      - `exp_year` number, required — The two-digit expiration year listed on the card (e.g. `21`).
      - `last_4` string, required — The last four digits of the card number.
      - `payment_method_id` string, required — The unique identifier for the Stripe PaymentMethod that represents the customer's payment instrument.
      - `psp_customer_id` string, required — The unique Stripe identifier for the cardholder.
      - `is_hsa_fsa` boolean — Indicates whether the card is an HSA/FSA card.
      - `bin` string — The BIN portion of the card number.
      - `issuer` string — The name of the card issuer.
      - `address_postal_code_check` 'pass' | 'fail' | 'unavailable' | 'unchecked' — The result of any check done on the delivery address zip code. One of: - `pass`: The provided information is correct and matches the data on file with the card issuer. - `fail`: The provided information is incorrect and does not match the data on file. - `unavailable`: The card issuer will not perform the check. - `unchecked`: The information was provided but has not yet been checked by the card issuer.
      - `cvc_check` 'pass' | 'fail' | 'unavailable' | 'unchecked' — The result of any check done on the CVC. One of: - `pass`: The provided information is correct and matches the data on file with the card issuer. - `fail`: The provided information is incorrect and does not match the data on file. - `unavailable`: The card issuer will not perform the check. - `unchecked`: The information was provided but has not yet been checked by the card issuer.
    - OtherNonEBTCard — If a [credit/debit PSP](https://docs.joinforage.app/docs/ebt-online-101#creditdebit-payment-service-provider-psp) other than Stripe processes the payment, then this object details information about the non-EBT Card.
      - `brand` 'amex' | 'discover' | 'mastercard' | 'visa', required — The card brand. One of: - `amex` - `discover` - `mastercard` - `visa`
      - `exp_month` number, required — The expiration month as listed on the card, without any preceding `0` (e.g. `4` instead of `04`).
      - `exp_year` number, required — The two-digit expiration year listed on the card (e.g. `21`).
      - `last_4` string, required — The last four digits of the card number.
      - `payment_profile_id` string, required — A unique PSP-provided identifier for the payment.
      - `customer_profile_id` string, required — A unique PSP-provided identifier for the customer.

## Response `200`

__OK__ - Success

- TokenizedPaymentMethod — This object represents a customer's payment instrument. It has been tokenized by the server. It does not include all details about the payment method. If the `PaymentMethod` has a type of `ebt`, then the `balance` field will be `null` until the `/api/payment_methods/{ref}/` endpoint is called. The `balance` field will always be `null` for non-EBT payment methods.
  - `ref` string — A unique reference identifier for the `PaymentMethod`. The `ref` is constant for a `customer_id` if the card is `reusable`.
  - `type` string — The card type. One of: - `credit` - `debit` - `prepaid` - `ebt` ⚠️ The `type` value can only be `credit`, `debit`, or `prepaid` in a [Fully Hosted](https://docs.joinforage.app/docs/fully-hosted) or [HSA/FSA](https://docs.joinforage.app/docs/enable-hsa-fsa-payments) integration.
  - `reusable` boolean — Whether the `PaymentMethod` can be reused. If `false`, then the `PaymentMethod` can only be used for a single transaction.
  - `card` union
    - EBTCardResponse — An object that details information about the EBT Card.
      - `last_4` string — The last four digits of the EBT Card number.
      - `created` string, date-time — A UTC timestamp that indicates when the EBT `PaymentMethod` was created, represented as an [ISO 8601 date-time](https://www.iso.org/iso-8601-date-and-time-format.html) string.
      - `token` string — A token that Forage can use to look up the EBT Card in secure storage.
      - `state` string — The two-letter abbreviation for the US state that issued the EBT Card (e.g. `CA`).
      - `fingerprint` string — ⚠️ Deprecated. Please use `fingerprint_v2` instead. A unique hash based on the card PAN. The `fingerprint` is constant for a card PAN, no matter the `customer_id`. Use the `fingerprint` to track card usage for fraud prevention.
      - `fingerprint_v2` string — A unique hash based on the card PAN. The `fingerprint_v2` is constant for a card PAN, no matter the `customer_id`. Use the `fingerprint_v2` to track card usage for fraud prevention.
    - NonEBTCard — If a [credit/debit PSP](https://docs.joinforage.app/docs/ebt-online-101#creditdebit-payment-service-provider-psp) other than Stripe processes the payment, then this object details information about the non-EBT Card.
      - `brand` 'amex' | 'discover' | 'mastercard' | 'visa', required — The card brand. One of: - `amex` - `discover` - `mastercard` - `visa`
      - `exp_month` number, required — The expiration month as listed on the card, without any preceding `0` (e.g. `4` instead of `04`).
      - `exp_year` number, required — The two-digit expiration year listed on the card (e.g. `21`).
      - `last_4` string, required — The last four digits of the card number.
    - StripeCard — If Stripe is the credit/debit [PSP](https://docs.joinforage.app/docs/ebt-online-101#creditdebit-payment-service-provider-psp), then this object details information about the non-EBT Card.
      - `brand` 'amex' | 'discover' | 'mastercard' | 'visa', required — The card brand. One of: - `amex` - `discover` - `mastercard` - `visa`
      - `exp_month` number, required — The expiration month as listed on the card, without any preceding `0` (e.g. `4` instead of `04`).
      - `exp_year` number, required — The two-digit expiration year listed on the card (e.g. `21`).
      - `last_4` string, required — The last four digits of the card number.
      - `payment_method_id` string, required — The unique identifier for the Stripe PaymentMethod that represents the customer's payment instrument.
      - `psp_customer_id` string, required — The unique Stripe identifier for the cardholder.
      - `is_hsa_fsa` boolean — Indicates whether the card is an HSA/FSA card.
      - `bin` string — The BIN portion of the card number.
      - `issuer` string — The name of the card issuer.
      - `address_postal_code_check` 'pass' | 'fail' | 'unavailable' | 'unchecked' — The result of any check done on the delivery address zip code. One of: - `pass`: The provided information is correct and matches the data on file with the card issuer. - `fail`: The provided information is incorrect and does not match the data on file. - `unavailable`: The card issuer will not perform the check. - `unchecked`: The information was provided but has not yet been checked by the card issuer.
      - `cvc_check` 'pass' | 'fail' | 'unavailable' | 'unchecked' — The result of any check done on the CVC. One of: - `pass`: The provided information is correct and matches the data on file with the card issuer. - `fail`: The provided information is incorrect and does not match the data on file. - `unavailable`: The card issuer will not perform the check. - `unchecked`: The information was provided but has not yet been checked by the card issuer.
  - `balance` BalanceResponse — An object that represents an EBT cardholder's account balance.
    - `id` integer — The unique identifier for the balance record.
    - `snap` string, currency — The available SNAP balance in USD on the customer’s EBT Card, represented as a numeric string.
    - `non_snap` string, currency — The available EBT Cash balance in USD on the customer's EBT Card, represented as a numeric string.
    - `updated` string, date-time — A UTC timestamp that indicates when the funds in the account last changed, represented as an [ISO 8601 date-time](https://www.iso.org/iso-8601-date-and-time-format.html) string.
    - `sequence_number` string — A transaction number for this `PaymentMethod`'s most recent balance check. Returned only for POS Terminal transactions; omitted from online merchant balance checks.
  - `customer_id` string — **⚠️ If you’re integrating Forage with a POS Terminal, then do not use this param. It is only supported for online transactions.** A unique identifier for the end customer making the payment. Forage automatically adds the `customer_id` to the Session's corresponding `Order` and `OrderPayments`. This field helps Forage's servers more quickly identify the customer associated with the request. While `customer_id` is not technically required, if you omit it then requests could take longer to process. **It is strongly recommended to pass customer_id.** If you're providing your internal customer ID, then we recommend that you hash the value before sending it on the payload. Each customer should only have one unique `customer_id`. For example, if you create both a `PaymentMethod` and a Forage `Session` (Fully Hosted or Custom) or `Payment` (SDK) for the same customer, then the `customer_id` should be the same in both requests to ensure continuity of stored payment methods.

## Other responses

- `400` — Bad Request
- `401` — Unauthorized
- `429` — Too Many Requests

---

[API](https://skmtc.dev/joinforage/apis/forage-payments-api.md) · [All operations](https://skmtc.dev/joinforage/apis/forage-payments-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/joinforage/forage-payments-api/revisions/4b7212706fae/schema)
