---
title: "Attach a payment method already vaulted at the gateway"
description: "For an instrument (card, mandate) that already lives in the gateway's vault — typically one brought across from another billing system on the same gateway account."
canonical_url: "https://twominutebilling.com/help/developers/api-reference/payment-methods/attach-a-payment-method-already-vaulted-at-the-g"
---
# Attach a payment method already vaulted at the gateway

> For an instrument (card, mandate) that already lives in the gateway's vault — typically one brought across from another billing system on the same gateway account.

<api-operation method="POST" path="/v1/businesses/{biz}/customers/{cus}/payment_methods/permanent_token">
<template v-slot:docs="">

Nothing is re-vaulted and nothing is charged. The gateway is asked first: an unknown token, or one owned by a different gateway customer, is refused. The gateway customer must match this customer's existing mapping on that account (one is recorded if there is none) and may not belong to another customer. Supported on gateways that can read back a vaulted instrument (Stripe, RazorPay); others answer 400.

## Path parameters

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Required
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        biz
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <strong>
        yes
      </strong>
    </td>
    
    <td>
      Business id (biz_…)
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        cus
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <strong>
        yes
      </strong>
    </td>
    
    <td>
      Customer id (cus_…)
    </td>
  </tr>
</tbody>
</table>

## Headers

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Required
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        Idempotency-Key
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      no
    </td>
    
    <td>
      Safely retry writes — repeats return the original response. If a write FAILED after it had already taken effect, that failure is what repeats: the key is spent, and a new attempt needs a new key.
    </td>
  </tr>
</tbody>
</table>

## Body

The request body is **required**.

<table>
<thead>
  <tr>
    <th>
      Field
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Required
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        reference_id
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      no
    </td>
    
    <td>
      <code>
        <gateway customer id>/<gateway token id>
      </code>
      
       (the <code>
        reference_id
      </code>
      
       a payment method returns), or the token alone. Exclusive with payment_method_token.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        payment_method_token
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      no
    </td>
    
    <td>
      The gateway's token id
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        gateway_customer_id
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      no
    </td>
    
    <td>
      The gateway customer that owns the token; defaults to this customer's existing mapping on the account
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        gateway_account
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      no
    </td>
    
    <td>
      Gateway account holding the token; required when the business has more than one active account
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        type
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      no
    </td>
    
    <td>
      Expected method type; refused if the gateway reports another
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        replace_primary_payment_source
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      no
    </td>
    
    <td>
      Make it the customer's primary payment method
    </td>
  </tr>
</tbody>
</table>

## Response

<table>
<thead>
  <tr>
    <th>
      Field
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        object
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      The object type.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        id
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      OUR id for the vaulted instrument. Not the gateway's — see reference_id.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        provider
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      The payment provider that holds the card.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        type
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      Instrument kind, e.g. card.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        brand
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      The card brand, e.g. <code>
        visa
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        last4
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      The last four digits of the card number.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        exp_month
      </code>
    </td>
    
    <td>
      <code>
        integer
      </code>
    </td>
    
    <td>
      The card's expiry month (1-12).
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        exp_year
      </code>
    </td>
    
    <td>
      <code>
        integer
      </code>
    </td>
    
    <td>
      The card's expiry year (four digits).
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        status
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      The payment method's status.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        role
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      primary | backup | none. <code>
        none
      </code>
      
       = excluded from automatic collection.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        is_default
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      Convenience for role === primary.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        gateway_account
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      Gateway account that vaulted (and will charge) this method; null for legacy env-configured providers with no gateway_accounts row.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        gateway_account_label
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      The label of the gateway account that holds this payment method.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        reference_id
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      The GATEWAY's reference for the instrument, <code>
        <gateway customer id>/<gateway token id>
      </code>
      
      . Token-only for gateways with no customer object of their own (PayPal). Null when the gateway supplied no token — render nothing rather than substituting the pm_… id.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        instrument
      </code>
    </td>
    
    <td>
      <code>
        object
      </code>
    </td>
    
    <td>
      What the gateway knows about the instrument itself. Null when it reported none of it. A null FIELD inside means that one fact is unknown — in particular a null <code>
        issuer_country
      </code>
      
       is UNKNOWN, never 'not issued in India'.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        mandate
      </code>
    </td>
    
    <td>
      <code>
        object
      </code>
    </td>
    
    <td>
      The mandate this instrument was registered under, as the PROVIDER reports it. Null on a plain card-on-file with no mandate rail. A null <code>
        max_amount_minor
      </code>
      
       means the provider reported no ceiling — unknown, NOT unlimited.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        avs_check
      </code>
    </td>
    
    <td>
      <code>
        object
      </code>
    </td>
    
    <td>
      What the gateway said about the address / CVC when this instrument was vaulted or charged. Null means nothing was captured — distinct from <code>
        unchecked
      </code>
      
      , which is a real verdict a gateway can send. Stripe only today.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        created_at
      </code>
    </td>
    
    <td>
      <code>
        string · ISO-8601
      </code>
    </td>
    
    <td>
      When the payment method was created (ISO-8601 UTC).
    </td>
  </tr>
</tbody>
</table>

## Status codes

<table>
<thead>
  <tr>
    <th>
      Status
    </th>
    
    <th>
      Meaning
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        201
      </code>
    </td>
    
    <td>
      Created
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        400
      </code>
    </td>
    
    <td>
      Unknown token / ownership mismatch / unsupported gateway
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        404
      </code>
    </td>
    
    <td>
      No such customer
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        409
      </code>
    </td>
    
    <td>
      Idempotency-Key conflict — the key is already in flight, or was reused with a different request payload.
    </td>
  </tr>
</tbody>
</table>
</template>

<template v-slot:request="">

```bash [Request]
curl -X POST "$TMBILLING_URL/v1/businesses/biz_XXXXXXXXXXXX01/customers/cus_XXXXXXXXXXXX01/payment_methods/permanent_token" \
  -H "Authorization: Bearer $TMBILLING_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "reference_id": "cus_XXXXXXXXXXXX01/pm_XXXXXXXXXXXX01",
    "payment_method_token": "tok_XXXXXXXXXXXX01"
  }'
```

</template>

<template v-slot:response="">
<code-group>

```json [201 Created]
{
  "object": "payment_method",
  "id": "pm_XXXXXXXXXXXX01",
  "provider": "stripe",
  "type": "card",
  "brand": "visa",
  "last4": "4242",
  "exp_month": 1,
  "exp_year": 2026,
  "status": "active",
  "role": "admin",
  "is_default": false,
  "gateway_account": "gwa_XXXXXXXXXXXX01",
  "gateway_account_label": "Razorpay-1",
  "reference_id": "cust_XXXXXXXXXXXXXX/token_XXXXXXXXXXXXXX",
  "instrument": {
    "funding": "credit",
    "sub_type": "consumer",
    "issuer_country": "IN",
    "issuer_name": "HDFC Bank",
    "fingerprint": "fp_XXXXXXXXXXXX01",
    "supports_international": false,
    "supports_recurring": false,
    "three_d_secure_supported": false
  },
  "mandate": {
    "rail": "emandate",
    "status": "confirmed",
    "max_amount_minor": 2900,
    "currency": "USD",
    "expires_at": "2026-04-14T09:30:00Z",
    "reference": "REF-1001"
  },
  "avs_check": {
    "line1": "pass",
    "postal_code": "pass",
    "cvc": "pass",
    "checked_at": "2026-03-14T09:30:00Z"
  },
  "created_at": "2026-03-14T09:30:00Z"
}
```

```json [400 Bad Request]
{
  "error": {
    "type": "invalid_request_error",
    "message": "Unknown token / ownership mismatch / unsupported gateway"
  }
}
```

```json [404 Not Found]
{
  "error": {
    "type": "invalid_request_error",
    "message": "No such customer"
  }
}
```

```json [409 Conflict]
{
  "error": {
    "type": "idempotency_error",
    "message": "Idempotency-Key conflict — the key is already in flight, or was reused with a different request payload."
  }
}
```

</code-group>
</template>
</api-operation>


## Sitemap

See the full [sitemap](https://twominutebilling.com/sitemap.md) for all pages.
