> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.coinflow.cash/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.coinflow.cash/_mcp/server.

# 📱 Apple Pay Subsequent Transactions

## Overview

Coinflow supports **Card on File (COF)** transactions for Apple Pay. Once a customer completes an initial Apple Pay purchase, Coinflow securely saves their Apple Pay card so you can process subsequent, customer-initiated purchases **without showing the Apple Pay sheet again** — no re-authentication with Face ID or Touch ID required.

This uses the same [Card on File Checkout endpoint](/api-reference/api-reference/checkout/card-on-file-checkout) as regular card payments. Coinflow automatically detects that the original payment was made with Apple Pay — no additional parameters are required.

> **Info**
>
> **Customer Initiated Only**
>
> Apple Pay subsequent transactions are supported for **Card on File (Customer Initiated) transactions only**. [Merchant Initiated Transactions (MIT)](/guides/checkout/payment-scenarios/subsequent-transactions/merchant-initiated-transactions) — such as automated subscription renewals — are not supported with Apple Pay. The customer must be present and actively confirming each purchase.

---

## How Apple Pay Cards Are Saved

When **Card on File is enabled** on your merchant account, every successful Apple Pay checkout automatically saves the customer's card:

### Customer Pays with Apple Pay

The customer completes a purchase through the Apple Pay sheet, authenticating with Face ID or Touch ID.

### Coinflow Saves the Card

Coinflow tokenizes the card behind the Apple Pay payment and stores it securely in Coinflow's PCI-compliant vault, attached to the customer's profile.

### Card Appears on the Customer Profile

The saved card is returned in the `mobiles` array of the [Get Customer](/api-reference/api-reference/customers/get-customer) response, including a display alias (e.g. "Visa 1234"), the card `token`, and expiration details.

### Request

GET [https://api-sandbox.coinflow.cash/api/customer/v2](https://api-sandbox.coinflow.cash/api/customer/v2)

**`Saved Apple Pay Cards`**

```curl Saved Apple Pay Cards
curl https://api-sandbox.coinflow.cash/api/customer/v2 \
     -H "x-coinflow-auth-session-key: <apiKey>"
```

**`Saved Apple Pay Cards`**

```python Saved Apple Pay Cards
import requests

url = "https://api-sandbox.coinflow.cash/api/customer/v2"

headers = {"x-coinflow-auth-session-key": "<apiKey>"}

response = requests.get(url, headers=headers)

print(response.json())
```

**`Saved Apple Pay Cards`**

```javascript Saved Apple Pay Cards
const url = 'https://api-sandbox.coinflow.cash/api/customer/v2';
const options = {method: 'GET', headers: {'x-coinflow-auth-session-key': '<apiKey>'}};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

**`Saved Apple Pay Cards`**

```go Saved Apple Pay Cards
package main

import (
	"fmt"
	"net/http"
	"io"
)

func main() {

	url := "https://api-sandbox.coinflow.cash/api/customer/v2"

	req, _ := http.NewRequest("GET", url, nil)

	req.Header.Add("x-coinflow-auth-session-key", "<apiKey>")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

**`Saved Apple Pay Cards`**

```ruby Saved Apple Pay Cards
require 'uri'
require 'net/http'

url = URI("https://api-sandbox.coinflow.cash/api/customer/v2")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)
request["x-coinflow-auth-session-key"] = '<apiKey>'

response = http.request(request)
puts response.read_body
```

**`Saved Apple Pay Cards`**

```java Saved Apple Pay Cards
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.get("https://api-sandbox.coinflow.cash/api/customer/v2")
  .header("x-coinflow-auth-session-key", "<apiKey>")
  .asString();
```

**`Saved Apple Pay Cards`**

```php Saved Apple Pay Cards
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('GET', 'https://api-sandbox.coinflow.cash/api/customer/v2', [
  'headers' => [
    'x-coinflow-auth-session-key' => '<apiKey>',
  ],
]);

echo $response->getBody();
```

**`Saved Apple Pay Cards`**

```csharp Saved Apple Pay Cards
using RestSharp;

var client = new RestClient("https://api-sandbox.coinflow.cash/api/customer/v2");
var request = new RestRequest(Method.GET);
request.AddHeader("x-coinflow-auth-session-key", "<apiKey>");
IRestResponse response = client.Execute(request);
```

**`Saved Apple Pay Cards`**

```swift Saved Apple Pay Cards
import Foundation

let headers = ["x-coinflow-auth-session-key": "<apiKey>"]

let request = NSMutableURLRequest(url: NSURL(string: "https://api-sandbox.coinflow.cash/api/customer/v2")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

### Response (200)

```json
{
  "customer": {
    "email": "string",
    "createdAt": "2024-01-15T09:30:00Z",
    "_id": "string",
    "merchant": "string",
    "customerId": "string",
    "bankAccounts": [
      {
        "last4": "string",
        "accountHash": "string",
        "alias": "string",
        "token": "string",
        "reference": "string"
      }
    ],
    "cards": [
      {
        "last4": "string",
        "token": "string",
        "type": "VISA",
        "disbursementStatus": "Immediate",
        "createdAt": "2024-01-15T09:30:00Z",
        "hasAddress": true
      }
    ],
    "sepas": [
      {
        "last4": "string",
        "accountHash": "string",
        "alias": "string",
        "token": "string",
        "reference": "string",
        "sortCode": "string"
      }
    ],
    "fasterPayments": [
      {
        "last4": "string",
        "accountHash": "string",
        "alias": "string",
        "token": "string",
        "reference": "string",
        "sortCode": "string"
      }
    ],
    "interacs": [
      {
        "alias": "string",
        "token": "string",
        "type": "interac"
      }
    ],
    "mobiles": [
      {
        "alias": "Visa 1234",
        "token": "4111114324324111_bt",
        "type": "mobile",
        "genus": "applepay",
        "hasAddress": true,
        "expMonth": "12",
        "expYear": "28"
      }
    ]
  }
}
```

> **Success**
>
> **No Extra Integration Work for Saving**
>
> Card saving happens automatically on every successful Apple Pay purchase when Card on File is enabled — there is no separate "save card" call.

---

## Prerequisites

Before processing Apple Pay subsequent transactions, make sure:

1. **Apple Pay is implemented** — See [Implement Apple Pay](/guides/checkout/payment-methods/payment-methods/apple-pay/implement-apple-pay#implementation)
2. **Card on File is enabled** on your merchant account — contact your Coinflow integration representative to enable it and configure your velocity limits
3. **An initial Apple Pay purchase is complete** — you need either the `paymentId` from that purchase or the saved card `token` from the customer profile

> **Warning**
>
> **Processing Configuration**
>
> Apple Pay Card on File is not available on every processing configuration. If your requests return `403 - Card on file not available`, contact your Coinflow integration representative.

---

## Implementation Guide

### Step 1: Complete the Initial Apple Pay Purchase

The customer's first purchase must go through the standard Apple Pay flow, where they authenticate on their device. After a successful purchase, save either of the following identifiers:

* The `paymentId` from the checkout response or [webhook](/guides/developer-resources/webhooks/checkout-webhooks)
* The card `token` from the `mobiles` array on the [Get Customer](/api-reference/api-reference/customers/get-customer) response

### Step 2 (Optional): Verify the Card Is Authorized

Before starting a session that depends on subsequent transactions (for example, an auction or a tab), confirm the saved card can still be charged:

### Request

POST [https://api-sandbox.coinflow.cash/api/checkout/card-on-file-authorized](https://api-sandbox.coinflow.cash/api/checkout/card-on-file-authorized)

```curl
curl -X POST https://api-sandbox.coinflow.cash/api/checkout/card-on-file-authorized \
     -H "x-coinflow-auth-user-id: <apiKey>" \
     -H "Content-Type: application/json" \
     -d '{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjYXJkSWQiOiIxMjM0NTY3ODkwIiwidXNlcklkIjoiYWJjZGVmMTIzNDU2IiwiaWF0IjoxNjgwMDAwMDAwfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
}'
```

```python
import requests

url = "https://api-sandbox.coinflow.cash/api/checkout/card-on-file-authorized"

payload = { "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjYXJkSWQiOiIxMjM0NTY3ODkwIiwidXNlcklkIjoiYWJjZGVmMTIzNDU2IiwiaWF0IjoxNjgwMDAwMDAwfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c" }
headers = {
    "x-coinflow-auth-user-id": "<apiKey>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript
const url = 'https://api-sandbox.coinflow.cash/api/checkout/card-on-file-authorized';
const options = {
  method: 'POST',
  headers: {'x-coinflow-auth-user-id': '<apiKey>', 'Content-Type': 'application/json'},
  body: '{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjYXJkSWQiOiIxMjM0NTY3ODkwIiwidXNlcklkIjoiYWJjZGVmMTIzNDU2IiwiaWF0IjoxNjgwMDAwMDAwfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api-sandbox.coinflow.cash/api/checkout/card-on-file-authorized"

	payload := strings.NewReader("{\n  \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjYXJkSWQiOiIxMjM0NTY3ODkwIiwidXNlcklkIjoiYWJjZGVmMTIzNDU2IiwiaWF0IjoxNjgwMDAwMDAwfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c\"\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("x-coinflow-auth-user-id", "<apiKey>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://api-sandbox.coinflow.cash/api/checkout/card-on-file-authorized")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["x-coinflow-auth-user-id"] = '<apiKey>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjYXJkSWQiOiIxMjM0NTY3ODkwIiwidXNlcklkIjoiYWJjZGVmMTIzNDU2IiwiaWF0IjoxNjgwMDAwMDAwfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c\"\n}"

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api-sandbox.coinflow.cash/api/checkout/card-on-file-authorized")
  .header("x-coinflow-auth-user-id", "<apiKey>")
  .header("Content-Type", "application/json")
  .body("{\n  \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjYXJkSWQiOiIxMjM0NTY3ODkwIiwidXNlcklkIjoiYWJjZGVmMTIzNDU2IiwiaWF0IjoxNjgwMDAwMDAwfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c\"\n}")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api-sandbox.coinflow.cash/api/checkout/card-on-file-authorized', [
  'body' => '{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjYXJkSWQiOiIxMjM0NTY3ODkwIiwidXNlcklkIjoiYWJjZGVmMTIzNDU2IiwiaWF0IjoxNjgwMDAwMDAwfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
}',
  'headers' => [
    'Content-Type' => 'application/json',
    'x-coinflow-auth-user-id' => '<apiKey>',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://api-sandbox.coinflow.cash/api/checkout/card-on-file-authorized");
var request = new RestRequest(Method.POST);
request.AddHeader("x-coinflow-auth-user-id", "<apiKey>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjYXJkSWQiOiIxMjM0NTY3ODkwIiwidXNlcklkIjoiYWJjZGVmMTIzNDU2IiwiaWF0IjoxNjgwMDAwMDAwfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c\"\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = [
  "x-coinflow-auth-user-id": "<apiKey>",
  "Content-Type": "application/json"
]
let parameters = ["token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjYXJkSWQiOiIxMjM0NTY3ODkwIiwidXNlcklkIjoiYWJjZGVmMTIzNDU2IiwiaWF0IjoxNjgwMDAwMDAwfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api-sandbox.coinflow.cash/api/checkout/card-on-file-authorized")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

### Response (200)

```json
{
  "authorized": true
}
```

If `authorized` is `false`, direct the customer through a fresh Apple Pay purchase to create a new original payment reference.

### Step 3: Process the Subsequent Transaction

Call the Card on File Checkout endpoint with either the original Apple Pay `paymentId` or the saved card `token`:

[View Card on File Checkout API Reference](/api-reference/api-reference/checkout/card-on-file-checkout)

**Using the Original Payment ID:**

### Request

POST [https://api-sandbox.coinflow.cash/api/checkout/card-on-file](https://api-sandbox.coinflow.cash/api/checkout/card-on-file)

**`Card Token`**

```curl Card Token
curl -X POST https://api-sandbox.coinflow.cash/api/checkout/card-on-file \
     -H "x-coinflow-auth-user-id: <apiKey>" \
     -H "Content-Type: application/json" \
     -d '{
  "subtotal": {
    "cents": 2500,
    "currency": "USD"
  },
  "token": "4111114324324111_bt"
}'
```

**`Card Token`**

```python Card Token
import requests

url = "https://api-sandbox.coinflow.cash/api/checkout/card-on-file"

payload = {
    "subtotal": {
        "cents": 2500,
        "currency": "USD"
    },
    "token": "4111114324324111_bt"
}
headers = {
    "x-coinflow-auth-user-id": "<apiKey>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

**`Card Token`**

```javascript Card Token
const url = 'https://api-sandbox.coinflow.cash/api/checkout/card-on-file';
const options = {
  method: 'POST',
  headers: {'x-coinflow-auth-user-id': '<apiKey>', 'Content-Type': 'application/json'},
  body: '{"subtotal":{"cents":2500,"currency":"USD"},"token":"4111114324324111_bt"}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

**`Card Token`**

```go Card Token
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api-sandbox.coinflow.cash/api/checkout/card-on-file"

	payload := strings.NewReader("{\n  \"subtotal\": {\n    \"cents\": 2500,\n    \"currency\": \"USD\"\n  },\n  \"token\": \"4111114324324111_bt\"\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("x-coinflow-auth-user-id", "<apiKey>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

**`Card Token`**

```ruby Card Token
require 'uri'
require 'net/http'

url = URI("https://api-sandbox.coinflow.cash/api/checkout/card-on-file")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["x-coinflow-auth-user-id"] = '<apiKey>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"subtotal\": {\n    \"cents\": 2500,\n    \"currency\": \"USD\"\n  },\n  \"token\": \"4111114324324111_bt\"\n}"

response = http.request(request)
puts response.read_body
```

**`Card Token`**

```java Card Token
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api-sandbox.coinflow.cash/api/checkout/card-on-file")
  .header("x-coinflow-auth-user-id", "<apiKey>")
  .header("Content-Type", "application/json")
  .body("{\n  \"subtotal\": {\n    \"cents\": 2500,\n    \"currency\": \"USD\"\n  },\n  \"token\": \"4111114324324111_bt\"\n}")
  .asString();
```

**`Card Token`**

```php Card Token
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api-sandbox.coinflow.cash/api/checkout/card-on-file', [
  'body' => '{
  "subtotal": {
    "cents": 2500,
    "currency": "USD"
  },
  "token": "4111114324324111_bt"
}',
  'headers' => [
    'Content-Type' => 'application/json',
    'x-coinflow-auth-user-id' => '<apiKey>',
  ],
]);

echo $response->getBody();
```

**`Card Token`**

```csharp Card Token
using RestSharp;

var client = new RestClient("https://api-sandbox.coinflow.cash/api/checkout/card-on-file");
var request = new RestRequest(Method.POST);
request.AddHeader("x-coinflow-auth-user-id", "<apiKey>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"subtotal\": {\n    \"cents\": 2500,\n    \"currency\": \"USD\"\n  },\n  \"token\": \"4111114324324111_bt\"\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

**`Card Token`**

```swift Card Token
import Foundation

let headers = [
  "x-coinflow-auth-user-id": "<apiKey>",
  "Content-Type": "application/json"
]
let parameters = [
  "subtotal": [
    "cents": 2500,
    "currency": "USD"
  ],
  "token": "4111114324324111_bt"
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api-sandbox.coinflow.cash/api/checkout/card-on-file")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

**Using the Card Token:**

### Request

POST [https://api-sandbox.coinflow.cash/api/checkout/card-on-file](https://api-sandbox.coinflow.cash/api/checkout/card-on-file)

**`Card Token`**

```curl Card Token
curl -X POST https://api-sandbox.coinflow.cash/api/checkout/card-on-file \
     -H "x-coinflow-auth-user-id: <apiKey>" \
     -H "Content-Type: application/json" \
     -d '{
  "subtotal": {
    "cents": 2500,
    "currency": "USD"
  },
  "token": "4111114324324111_bt"
}'
```

**`Card Token`**

```python Card Token
import requests

url = "https://api-sandbox.coinflow.cash/api/checkout/card-on-file"

payload = {
    "subtotal": {
        "cents": 2500,
        "currency": "USD"
    },
    "token": "4111114324324111_bt"
}
headers = {
    "x-coinflow-auth-user-id": "<apiKey>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

**`Card Token`**

```javascript Card Token
const url = 'https://api-sandbox.coinflow.cash/api/checkout/card-on-file';
const options = {
  method: 'POST',
  headers: {'x-coinflow-auth-user-id': '<apiKey>', 'Content-Type': 'application/json'},
  body: '{"subtotal":{"cents":2500,"currency":"USD"},"token":"4111114324324111_bt"}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

**`Card Token`**

```go Card Token
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api-sandbox.coinflow.cash/api/checkout/card-on-file"

	payload := strings.NewReader("{\n  \"subtotal\": {\n    \"cents\": 2500,\n    \"currency\": \"USD\"\n  },\n  \"token\": \"4111114324324111_bt\"\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("x-coinflow-auth-user-id", "<apiKey>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

**`Card Token`**

```ruby Card Token
require 'uri'
require 'net/http'

url = URI("https://api-sandbox.coinflow.cash/api/checkout/card-on-file")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["x-coinflow-auth-user-id"] = '<apiKey>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"subtotal\": {\n    \"cents\": 2500,\n    \"currency\": \"USD\"\n  },\n  \"token\": \"4111114324324111_bt\"\n}"

response = http.request(request)
puts response.read_body
```

**`Card Token`**

```java Card Token
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api-sandbox.coinflow.cash/api/checkout/card-on-file")
  .header("x-coinflow-auth-user-id", "<apiKey>")
  .header("Content-Type", "application/json")
  .body("{\n  \"subtotal\": {\n    \"cents\": 2500,\n    \"currency\": \"USD\"\n  },\n  \"token\": \"4111114324324111_bt\"\n}")
  .asString();
```

**`Card Token`**

```php Card Token
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api-sandbox.coinflow.cash/api/checkout/card-on-file', [
  'body' => '{
  "subtotal": {
    "cents": 2500,
    "currency": "USD"
  },
  "token": "4111114324324111_bt"
}',
  'headers' => [
    'Content-Type' => 'application/json',
    'x-coinflow-auth-user-id' => '<apiKey>',
  ],
]);

echo $response->getBody();
```

**`Card Token`**

```csharp Card Token
using RestSharp;

var client = new RestClient("https://api-sandbox.coinflow.cash/api/checkout/card-on-file");
var request = new RestRequest(Method.POST);
request.AddHeader("x-coinflow-auth-user-id", "<apiKey>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"subtotal\": {\n    \"cents\": 2500,\n    \"currency\": \"USD\"\n  },\n  \"token\": \"4111114324324111_bt\"\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

**`Card Token`**

```swift Card Token
import Foundation

let headers = [
  "x-coinflow-auth-user-id": "<apiKey>",
  "Content-Type": "application/json"
]
let parameters = [
  "subtotal": [
    "cents": 2500,
    "currency": "USD"
  ],
  "token": "4111114324324111_bt"
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api-sandbox.coinflow.cash/api/checkout/card-on-file")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

**Response:**

### Response (200)

```json
{
  "paymentId": "string"
}
```

> **Info**
>
> **Example Values**
>
> The IDs, tokens, and amounts above are **examples only** and do not reflect real production values. Use the identifiers returned by your own checkout responses, webhooks, and customer profiles.

> **Info**
>
> **Original Payment Must Be Apple Pay**
>
> The `originalPaymentId` must reference a successful **Apple Pay** purchase, and a `token` must belong to a saved Apple Pay card. You cannot mix payment sources — referencing a regular card payment for an Apple Pay saved card (or vice versa) returns a `400` error.

### Step 4: Handle Chargeback Protection (If Enabled)

If chargeback protection is enabled on your account, include the Coinflow device ID header and `chargebackProtectionData` in the request, exactly as with regular [Card on File transactions](/guides/checkout/payment-scenarios/subsequent-transactions/card-on-file#step-3-handle-chargeback-protection-if-enabled).

---

## Handling Expired References (410 Errors)

> **Warning**
>
> **Every integration must handle 410 responses**
>
> A `410 Gone` response means the original Apple Pay payment can no longer be used as a Card on File reference. Unlike regular card payments, there is no CVV re-entry fallback for Apple Pay — **the only way to recover is for the customer to complete a new purchase through the Apple Pay sheet**, which creates a fresh original payment reference.

A `410` is returned when any of your Card on File velocity limits are hit:

| Limit            | Setting               | When It Triggers                                                              |
| ---------------- | --------------------- | ----------------------------------------------------------------------------- |
| Payment count    | `maxCount` / `period` | Too many Card on File payments against the original payment within the period |
| Amount           | `maxMultiple`         | The transaction exceeds the allowed multiple of the original payment amount   |
| Reference window | `expiration`          | Too much time has passed since the original Apple Pay purchase                |

**Recommended flow:**

```javascript
async function chargeSavedApplePayCard({originalPaymentId, subtotal}) {
  const response = await fetch('/api/checkout/card-on-file', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Authorization: 'your-merchant-api-key',
      'x-coinflow-auth-user-id': 'your-customer-id',
    },
    body: JSON.stringify({subtotal, originalPaymentId}),
  });

  if (response.status === 410) {
    // The reference is exhausted or expired. Show a friendly message and
    // re-present the Apple Pay sheet so the customer authenticates on-device.
    // The new purchase becomes the original payment reference going forward.
    return promptApplePayPurchase({subtotal});
  }

  if (!response.ok) throw new Error((await response.json()).message);
  return response.json();
}
```

> **Tip**
>
> **Avoid 410s Mid-Session**
>
> Call [`POST /checkout/card-on-file-authorized`](/api-reference/api-reference/checkout/card-on-file-authorized) before starting a session that depends on subsequent transactions (an auction, a tab, a table). It runs the same velocity checks with a zero-amount total, so you can route the customer through a fresh Apple Pay purchase **before** they are mid-session rather than failing at charge time.

---

## Differences from Regular Card on File

| Feature                  |  Card on File (Regular Card) |                        Card on File (Apple Pay)                        |
| ------------------------ | :--------------------------: | :--------------------------------------------------------------------: |
| Endpoint                 | `/api/checkout/card-on-file` |                      `/api/checkout/card-on-file`                      |
| CVV Required             |              No              |                                   No                                   |
| 3DS Eligible             |              Yes             | No — the customer authenticated on-device during the original purchase |
| Original Payment         |   CVV-verified card payment  |                      Successful Apple Pay purchase                     |
| Merchant Initiated (MIT) |           Supported          |                              Not supported                             |
| Velocity Limits          |     Card on File settings    |                       Same Card on File settings                       |

Velocity limits (`maxCount`, `period`, `maxMultiple`, `expiration`) are shared with your regular [Card on File configuration](/guides/checkout/payment-scenarios/subsequent-transactions/card-on-file#merchant-configuration-settings).

---

## Error Handling

#### 403 Forbidden - Card on File Not Enabled

**Error Message:**

```
{merchantId} does not support card on file transactions
```

**Cause:** Card on File is not enabled or not configured on your merchant account.

**Resolution:** Contact your Coinflow integration representative to enable Card on File.

#### 403 Forbidden - Card on File Not Available

**Error Message:**

```
Card on file not available. Please contact your integrations representative.
```

**Cause:** Your processing configuration does not support Apple Pay Card on File.

**Resolution:** Contact your Coinflow integration representative.

#### 400 Bad Request - Different Payment Source

**Error Message:**

```
Cannot perform card on file operations with different payment source
```

**Cause:** The `originalPaymentId` references a payment made with a different payment source — for example, a regular card payment when charging a saved Apple Pay card, or a mobile wallet other than Apple Pay.

**Resolution:**

* Only reference an original payment made with **Apple Pay**
* Google Pay payments cannot be used for subsequent transactions

#### 400 Bad Request - Chained Card on File Payment

**Error Message:**

```
Cannot perform card on file operations for a originalPaymentId which is a card on file transaction,
please pass the originalPaymentId which processed with ApplePay
```

**Cause:** The `originalPaymentId` references a Card on File payment rather than the original Apple Pay purchase.

**Resolution:** Always reference the initial Apple Pay purchase — do not chain Card on File transactions.

#### 410 Gone - Velocity Limit Errors

The original payment reference can no longer be used — a velocity limit was hit or the reference window expired. See [Handling Expired References](#handling-expired-references-410-errors) above for the recovery flow, and the [Card on File error reference](/guides/checkout/payment-scenarios/subsequent-transactions/card-on-file#error-handling) for the exact error messages.

---

## Frequently Asked Questions

#### Does the customer need to re-authenticate with Face ID or Touch ID?

No. Subsequent transactions run against the saved card without presenting the
Apple Pay sheet. The customer's on-device authentication from the original
purchase serves as the cardholder verification.

#### Is Google Pay supported?

No. Subsequent transactions are currently supported for Apple Pay only.
Google Pay customers must authenticate through the Google Pay flow for every
purchase.

#### Can I use a saved Apple Pay card for subscriptions or other Merchant Initiated Transactions?

No. Apple Pay saved cards support Customer Initiated (Card on File)
transactions only — the customer must actively confirm each purchase in your
application.

#### How do I show the customer which card will be charged?

Use the `mobiles` array on the [Get Customer](/api-reference/api-reference/customers/get-customer)
response. Each saved Apple Pay card includes an `alias` (the card's display
name from Apple Pay, e.g. "Visa 1234") you can show at confirmation.

---

## Next Steps

#### [Implement Apple Pay](/guides/checkout/payment-methods/payment-methods/apple-pay/implement-apple-pay)

Set up the initial Apple Pay purchase flow

#### [Card on File](/guides/checkout/payment-scenarios/subsequent-transactions/card-on-file)

Learn how Card on File works for regular card payments

#### [Webhooks](/guides/developer-resources/webhooks/checkout-webhooks)

Get notified about payment results

#### [Merchant Initiated Transactions](/guides/checkout/payment-scenarios/subsequent-transactions/merchant-initiated-transactions)

Automated charges with regular card payments