Create card session
curl --request POST \
--url https://api.natural.com/card-sessions \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"data": {
"attributes": {
"cardId": "eac_01a0e642ed4873d685273ce0e7d1ccab",
"purchase": {
"merchantName": "Blue Bottle Coffee",
"amount": 2450,
"currency": "USD",
"description": "Two bags of whole bean coffee"
},
"allowedHosts": [
"api.stripe.com"
],
"ttlSeconds": 600,
"claimWindowSeconds": 3600,
"reference": "checkout_7f3a",
"returnUrl": "sms:+15551234567",
"requestAgentToken": true
}
}
}
'import requests
url = "https://api.natural.com/card-sessions"
payload = { "data": { "attributes": {
"cardId": "eac_01a0e642ed4873d685273ce0e7d1ccab",
"purchase": {
"merchantName": "Blue Bottle Coffee",
"amount": 2450,
"currency": "USD",
"description": "Two bags of whole bean coffee"
},
"allowedHosts": ["api.stripe.com"],
"ttlSeconds": 600,
"claimWindowSeconds": 3600,
"reference": "checkout_7f3a",
"returnUrl": "sms:+15551234567",
"requestAgentToken": True
} } }
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
data: {
attributes: {
cardId: 'eac_01a0e642ed4873d685273ce0e7d1ccab',
purchase: {
merchantName: 'Blue Bottle Coffee',
amount: 2450,
currency: 'USD',
description: 'Two bags of whole bean coffee'
},
allowedHosts: ['api.stripe.com'],
ttlSeconds: 600,
claimWindowSeconds: 3600,
reference: 'checkout_7f3a',
returnUrl: 'sms:+15551234567',
requestAgentToken: true
}
}
})
};
fetch('https://api.natural.com/card-sessions', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.natural.com/card-sessions",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'data' => [
'attributes' => [
'cardId' => 'eac_01a0e642ed4873d685273ce0e7d1ccab',
'purchase' => [
'merchantName' => 'Blue Bottle Coffee',
'amount' => 2450,
'currency' => 'USD',
'description' => 'Two bags of whole bean coffee'
],
'allowedHosts' => [
'api.stripe.com'
],
'ttlSeconds' => 600,
'claimWindowSeconds' => 3600,
'reference' => 'checkout_7f3a',
'returnUrl' => 'sms:+15551234567',
'requestAgentToken' => true
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.natural.com/card-sessions"
payload := strings.NewReader("{\n \"data\": {\n \"attributes\": {\n \"cardId\": \"eac_01a0e642ed4873d685273ce0e7d1ccab\",\n \"purchase\": {\n \"merchantName\": \"Blue Bottle Coffee\",\n \"amount\": 2450,\n \"currency\": \"USD\",\n \"description\": \"Two bags of whole bean coffee\"\n },\n \"allowedHosts\": [\n \"api.stripe.com\"\n ],\n \"ttlSeconds\": 600,\n \"claimWindowSeconds\": 3600,\n \"reference\": \"checkout_7f3a\",\n \"returnUrl\": \"sms:+15551234567\",\n \"requestAgentToken\": true\n }\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.natural.com/card-sessions")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"data\": {\n \"attributes\": {\n \"cardId\": \"eac_01a0e642ed4873d685273ce0e7d1ccab\",\n \"purchase\": {\n \"merchantName\": \"Blue Bottle Coffee\",\n \"amount\": 2450,\n \"currency\": \"USD\",\n \"description\": \"Two bags of whole bean coffee\"\n },\n \"allowedHosts\": [\n \"api.stripe.com\"\n ],\n \"ttlSeconds\": 600,\n \"claimWindowSeconds\": 3600,\n \"reference\": \"checkout_7f3a\",\n \"returnUrl\": \"sms:+15551234567\",\n \"requestAgentToken\": true\n }\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.natural.com/card-sessions")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"data\": {\n \"attributes\": {\n \"cardId\": \"eac_01a0e642ed4873d685273ce0e7d1ccab\",\n \"purchase\": {\n \"merchantName\": \"Blue Bottle Coffee\",\n \"amount\": 2450,\n \"currency\": \"USD\",\n \"description\": \"Two bags of whole bean coffee\"\n },\n \"allowedHosts\": [\n \"api.stripe.com\"\n ],\n \"ttlSeconds\": 600,\n \"claimWindowSeconds\": 3600,\n \"reference\": \"checkout_7f3a\",\n \"returnUrl\": \"sms:+15551234567\",\n \"requestAgentToken\": true\n }\n }\n}"
response = http.request(request)
puts response.read_body{
"sessionId": "csn_01a0e6466ba3713bba0f0d9d36803b92",
"cardId": "eac_01a0e642ed4873d685273ce0e7d1ccab",
"cardSource": "external",
"status": "pending_approval",
"allowedHosts": [
"api.stripe.com"
],
"reference": "checkout_7f3a",
"purchase": {
"merchantName": "Blue Bottle Coffee",
"amount": 2450,
"currency": "USD",
"description": "Two bags of whole bean coffee"
},
"approvalExpiresAt": "2026-09-30T18:00:00.000Z",
"claimExpiresAt": "2026-09-30T19:00:00.000Z",
"claimedAt": null,
"credentialExpiresAt": null,
"createdAt": "2026-09-29T18:00:00.000Z",
"agentToken": {
"requested": true,
"mandateId": null
},
"note": null,
"approvalUrl": "https://natural.com/dashboard/card-approvals/QO9J1KqnWOZT5dY6W7sT5w?returnTo=sms%3A%2B15551234567"
}{
"errors": [
{
"code": "invalid_value",
"detail": "The information you entered isn't valid. Please check it and try again.",
"status": "400",
"meta": {
"supportId": "req_a1b2c3d4e5f6"
}
}
]
}{
"errors": [
{
"code": "unauthenticated",
"detail": "Authentication is required.",
"status": "401",
"meta": {
"supportId": "req_a1b2c3d4e5f6"
}
}
]
}{
"errors": [
{
"code": "forbidden",
"detail": "You do not have permission to perform this action.",
"status": "403",
"meta": {
"supportId": "req_a1b2c3d4e5f6"
}
}
]
}{
"errors": [
{
"code": "not_found",
"detail": "The requested resource was not found.",
"status": "404",
"meta": {
"supportId": "req_a1b2c3d4e5f6"
}
}
]
}{
"errors": [
{
"code": "conflict",
"detail": "The request conflicts with the current resource state.",
"status": "409",
"meta": {
"supportId": "req_a1b2c3d4e5f6"
}
}
]
}{
"errors": [
{
"code": "invalid_value",
"detail": "Too big: expected string to have <=80 characters",
"status": "422",
"source": {
"pointer": "/data/attributes/description"
},
"meta": {
"supportId": "req_a1b2c3d4e5f6"
}
}
]
}{
"errors": [
{
"code": "mfa_required",
"detail": "MFA verification required.",
"status": "428",
"meta": {
"supportId": "req_a1b2c3d4e5f6"
}
}
]
}{
"errors": [
{
"code": "rate_limited",
"detail": "Too many requests. Please try again later.",
"status": "429",
"meta": {
"supportId": "req_a1b2c3d4e5f6"
}
}
]
}{
"errors": [
{
"code": "server_error",
"detail": "Something went wrong.",
"status": "500",
"meta": {
"supportId": "req_a1b2c3d4e5f6"
}
}
]
}{
"errors": [
{
"code": "not_implemented",
"detail": "This operation is not available.",
"status": "501",
"meta": {
"supportId": "req_a1b2c3d4e5f6"
}
}
]
}{
"errors": [
{
"code": "bad_gateway",
"detail": "We couldn't complete that request because one of Natural's services returned an unexpected response. Please try again.",
"status": "502",
"meta": {
"supportId": "req_a1b2c3d4e5f6"
}
}
]
}{
"errors": [
{
"code": "service_unavailable",
"detail": "The service is temporarily unavailable.",
"status": "503",
"meta": {
"supportId": "req_a1b2c3d4e5f6"
}
}
]
}Browser tokens
Create card session
Open a session to pay for one purchase with one card. Poll it until the user approves, then claim it once for a stand-in card and proxy login.
POST
/
card-sessions
Create card session
curl --request POST \
--url https://api.natural.com/card-sessions \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"data": {
"attributes": {
"cardId": "eac_01a0e642ed4873d685273ce0e7d1ccab",
"purchase": {
"merchantName": "Blue Bottle Coffee",
"amount": 2450,
"currency": "USD",
"description": "Two bags of whole bean coffee"
},
"allowedHosts": [
"api.stripe.com"
],
"ttlSeconds": 600,
"claimWindowSeconds": 3600,
"reference": "checkout_7f3a",
"returnUrl": "sms:+15551234567",
"requestAgentToken": true
}
}
}
'import requests
url = "https://api.natural.com/card-sessions"
payload = { "data": { "attributes": {
"cardId": "eac_01a0e642ed4873d685273ce0e7d1ccab",
"purchase": {
"merchantName": "Blue Bottle Coffee",
"amount": 2450,
"currency": "USD",
"description": "Two bags of whole bean coffee"
},
"allowedHosts": ["api.stripe.com"],
"ttlSeconds": 600,
"claimWindowSeconds": 3600,
"reference": "checkout_7f3a",
"returnUrl": "sms:+15551234567",
"requestAgentToken": True
} } }
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
data: {
attributes: {
cardId: 'eac_01a0e642ed4873d685273ce0e7d1ccab',
purchase: {
merchantName: 'Blue Bottle Coffee',
amount: 2450,
currency: 'USD',
description: 'Two bags of whole bean coffee'
},
allowedHosts: ['api.stripe.com'],
ttlSeconds: 600,
claimWindowSeconds: 3600,
reference: 'checkout_7f3a',
returnUrl: 'sms:+15551234567',
requestAgentToken: true
}
}
})
};
fetch('https://api.natural.com/card-sessions', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.natural.com/card-sessions",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'data' => [
'attributes' => [
'cardId' => 'eac_01a0e642ed4873d685273ce0e7d1ccab',
'purchase' => [
'merchantName' => 'Blue Bottle Coffee',
'amount' => 2450,
'currency' => 'USD',
'description' => 'Two bags of whole bean coffee'
],
'allowedHosts' => [
'api.stripe.com'
],
'ttlSeconds' => 600,
'claimWindowSeconds' => 3600,
'reference' => 'checkout_7f3a',
'returnUrl' => 'sms:+15551234567',
'requestAgentToken' => true
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.natural.com/card-sessions"
payload := strings.NewReader("{\n \"data\": {\n \"attributes\": {\n \"cardId\": \"eac_01a0e642ed4873d685273ce0e7d1ccab\",\n \"purchase\": {\n \"merchantName\": \"Blue Bottle Coffee\",\n \"amount\": 2450,\n \"currency\": \"USD\",\n \"description\": \"Two bags of whole bean coffee\"\n },\n \"allowedHosts\": [\n \"api.stripe.com\"\n ],\n \"ttlSeconds\": 600,\n \"claimWindowSeconds\": 3600,\n \"reference\": \"checkout_7f3a\",\n \"returnUrl\": \"sms:+15551234567\",\n \"requestAgentToken\": true\n }\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.natural.com/card-sessions")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"data\": {\n \"attributes\": {\n \"cardId\": \"eac_01a0e642ed4873d685273ce0e7d1ccab\",\n \"purchase\": {\n \"merchantName\": \"Blue Bottle Coffee\",\n \"amount\": 2450,\n \"currency\": \"USD\",\n \"description\": \"Two bags of whole bean coffee\"\n },\n \"allowedHosts\": [\n \"api.stripe.com\"\n ],\n \"ttlSeconds\": 600,\n \"claimWindowSeconds\": 3600,\n \"reference\": \"checkout_7f3a\",\n \"returnUrl\": \"sms:+15551234567\",\n \"requestAgentToken\": true\n }\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.natural.com/card-sessions")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"data\": {\n \"attributes\": {\n \"cardId\": \"eac_01a0e642ed4873d685273ce0e7d1ccab\",\n \"purchase\": {\n \"merchantName\": \"Blue Bottle Coffee\",\n \"amount\": 2450,\n \"currency\": \"USD\",\n \"description\": \"Two bags of whole bean coffee\"\n },\n \"allowedHosts\": [\n \"api.stripe.com\"\n ],\n \"ttlSeconds\": 600,\n \"claimWindowSeconds\": 3600,\n \"reference\": \"checkout_7f3a\",\n \"returnUrl\": \"sms:+15551234567\",\n \"requestAgentToken\": true\n }\n }\n}"
response = http.request(request)
puts response.read_body{
"sessionId": "csn_01a0e6466ba3713bba0f0d9d36803b92",
"cardId": "eac_01a0e642ed4873d685273ce0e7d1ccab",
"cardSource": "external",
"status": "pending_approval",
"allowedHosts": [
"api.stripe.com"
],
"reference": "checkout_7f3a",
"purchase": {
"merchantName": "Blue Bottle Coffee",
"amount": 2450,
"currency": "USD",
"description": "Two bags of whole bean coffee"
},
"approvalExpiresAt": "2026-09-30T18:00:00.000Z",
"claimExpiresAt": "2026-09-30T19:00:00.000Z",
"claimedAt": null,
"credentialExpiresAt": null,
"createdAt": "2026-09-29T18:00:00.000Z",
"agentToken": {
"requested": true,
"mandateId": null
},
"note": null,
"approvalUrl": "https://natural.com/dashboard/card-approvals/QO9J1KqnWOZT5dY6W7sT5w?returnTo=sms%3A%2B15551234567"
}{
"errors": [
{
"code": "invalid_value",
"detail": "The information you entered isn't valid. Please check it and try again.",
"status": "400",
"meta": {
"supportId": "req_a1b2c3d4e5f6"
}
}
]
}{
"errors": [
{
"code": "unauthenticated",
"detail": "Authentication is required.",
"status": "401",
"meta": {
"supportId": "req_a1b2c3d4e5f6"
}
}
]
}{
"errors": [
{
"code": "forbidden",
"detail": "You do not have permission to perform this action.",
"status": "403",
"meta": {
"supportId": "req_a1b2c3d4e5f6"
}
}
]
}{
"errors": [
{
"code": "not_found",
"detail": "The requested resource was not found.",
"status": "404",
"meta": {
"supportId": "req_a1b2c3d4e5f6"
}
}
]
}{
"errors": [
{
"code": "conflict",
"detail": "The request conflicts with the current resource state.",
"status": "409",
"meta": {
"supportId": "req_a1b2c3d4e5f6"
}
}
]
}{
"errors": [
{
"code": "invalid_value",
"detail": "Too big: expected string to have <=80 characters",
"status": "422",
"source": {
"pointer": "/data/attributes/description"
},
"meta": {
"supportId": "req_a1b2c3d4e5f6"
}
}
]
}{
"errors": [
{
"code": "mfa_required",
"detail": "MFA verification required.",
"status": "428",
"meta": {
"supportId": "req_a1b2c3d4e5f6"
}
}
]
}{
"errors": [
{
"code": "rate_limited",
"detail": "Too many requests. Please try again later.",
"status": "429",
"meta": {
"supportId": "req_a1b2c3d4e5f6"
}
}
]
}{
"errors": [
{
"code": "server_error",
"detail": "Something went wrong.",
"status": "500",
"meta": {
"supportId": "req_a1b2c3d4e5f6"
}
}
]
}{
"errors": [
{
"code": "not_implemented",
"detail": "This operation is not available.",
"status": "501",
"meta": {
"supportId": "req_a1b2c3d4e5f6"
}
}
]
}{
"errors": [
{
"code": "bad_gateway",
"detail": "We couldn't complete that request because one of Natural's services returned an unexpected response. Please try again.",
"status": "502",
"meta": {
"supportId": "req_a1b2c3d4e5f6"
}
}
]
}{
"errors": [
{
"code": "service_unavailable",
"detail": "The service is temporarily unavailable.",
"status": "503",
"meta": {
"supportId": "req_a1b2c3d4e5f6"
}
}
]
}Authorizations
Headers
Response
Successful Response
Was this page helpful?