curl --request POST \
--url https://api.farthing.ai/v1/buyer-profiles \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"label": "ada-home",
"name": {
"first": "Ada",
"last": "Lovelace"
},
"contact": {
"email": "ada@example.com",
"phone": "+15555550123"
},
"shipping": {
"addressLines": [
"1 Analytical Way"
],
"locality": "Louisville",
"administrativeAreaCode": "KY",
"postalCode": "40202",
"countryCode": "US"
}
}
'import requests
url = "https://api.farthing.ai/v1/buyer-profiles"
payload = {
"label": "ada-home",
"name": {
"first": "Ada",
"last": "Lovelace"
},
"contact": {
"email": "ada@example.com",
"phone": "+15555550123"
},
"shipping": {
"addressLines": ["1 Analytical Way"],
"locality": "Louisville",
"administrativeAreaCode": "KY",
"postalCode": "40202",
"countryCode": "US"
}
}
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({
label: 'ada-home',
name: {first: 'Ada', last: 'Lovelace'},
contact: {email: 'ada@example.com', phone: '+15555550123'},
shipping: {
addressLines: ['1 Analytical Way'],
locality: 'Louisville',
administrativeAreaCode: 'KY',
postalCode: '40202',
countryCode: 'US'
}
})
};
fetch('https://api.farthing.ai/v1/buyer-profiles', 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.farthing.ai/v1/buyer-profiles",
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([
'label' => 'ada-home',
'name' => [
'first' => 'Ada',
'last' => 'Lovelace'
],
'contact' => [
'email' => 'ada@example.com',
'phone' => '+15555550123'
],
'shipping' => [
'addressLines' => [
'1 Analytical Way'
],
'locality' => 'Louisville',
'administrativeAreaCode' => 'KY',
'postalCode' => '40202',
'countryCode' => 'US'
]
]),
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.farthing.ai/v1/buyer-profiles"
payload := strings.NewReader("{\n \"label\": \"ada-home\",\n \"name\": {\n \"first\": \"Ada\",\n \"last\": \"Lovelace\"\n },\n \"contact\": {\n \"email\": \"ada@example.com\",\n \"phone\": \"+15555550123\"\n },\n \"shipping\": {\n \"addressLines\": [\n \"1 Analytical Way\"\n ],\n \"locality\": \"Louisville\",\n \"administrativeAreaCode\": \"KY\",\n \"postalCode\": \"40202\",\n \"countryCode\": \"US\"\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.farthing.ai/v1/buyer-profiles")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"label\": \"ada-home\",\n \"name\": {\n \"first\": \"Ada\",\n \"last\": \"Lovelace\"\n },\n \"contact\": {\n \"email\": \"ada@example.com\",\n \"phone\": \"+15555550123\"\n },\n \"shipping\": {\n \"addressLines\": [\n \"1 Analytical Way\"\n ],\n \"locality\": \"Louisville\",\n \"administrativeAreaCode\": \"KY\",\n \"postalCode\": \"40202\",\n \"countryCode\": \"US\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.farthing.ai/v1/buyer-profiles")
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 \"label\": \"ada-home\",\n \"name\": {\n \"first\": \"Ada\",\n \"last\": \"Lovelace\"\n },\n \"contact\": {\n \"email\": \"ada@example.com\",\n \"phone\": \"+15555550123\"\n },\n \"shipping\": {\n \"addressLines\": [\n \"1 Analytical Way\"\n ],\n \"locality\": \"Louisville\",\n \"administrativeAreaCode\": \"KY\",\n \"postalCode\": \"40202\",\n \"countryCode\": \"US\"\n }\n}"
response = http.request(request)
puts response.read_body{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"label": "<string>",
"subject": "user_a91f",
"name": {},
"contact": {},
"shipping": {},
"createdAt": "2023-11-07T05:31:56Z"
}Create a buyer profile
Every field is optional — {} is a valid profile — but the agent can only fill what you gave it. Values are stored and typed exactly as sent: no normalisation, no address validation, no correction.
One profile per end user. A profile is the identity that stored merchant sessions hang off, so reusing one across unrelated buyers would share their merchant logins.
Requires the buyer-profiles.write scope.
Set subject to say which of your end users this profile is for. A key bound to that subject can then reach it and no other end user’s key can.
curl --request POST \
--url https://api.farthing.ai/v1/buyer-profiles \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"label": "ada-home",
"name": {
"first": "Ada",
"last": "Lovelace"
},
"contact": {
"email": "ada@example.com",
"phone": "+15555550123"
},
"shipping": {
"addressLines": [
"1 Analytical Way"
],
"locality": "Louisville",
"administrativeAreaCode": "KY",
"postalCode": "40202",
"countryCode": "US"
}
}
'import requests
url = "https://api.farthing.ai/v1/buyer-profiles"
payload = {
"label": "ada-home",
"name": {
"first": "Ada",
"last": "Lovelace"
},
"contact": {
"email": "ada@example.com",
"phone": "+15555550123"
},
"shipping": {
"addressLines": ["1 Analytical Way"],
"locality": "Louisville",
"administrativeAreaCode": "KY",
"postalCode": "40202",
"countryCode": "US"
}
}
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({
label: 'ada-home',
name: {first: 'Ada', last: 'Lovelace'},
contact: {email: 'ada@example.com', phone: '+15555550123'},
shipping: {
addressLines: ['1 Analytical Way'],
locality: 'Louisville',
administrativeAreaCode: 'KY',
postalCode: '40202',
countryCode: 'US'
}
})
};
fetch('https://api.farthing.ai/v1/buyer-profiles', 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.farthing.ai/v1/buyer-profiles",
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([
'label' => 'ada-home',
'name' => [
'first' => 'Ada',
'last' => 'Lovelace'
],
'contact' => [
'email' => 'ada@example.com',
'phone' => '+15555550123'
],
'shipping' => [
'addressLines' => [
'1 Analytical Way'
],
'locality' => 'Louisville',
'administrativeAreaCode' => 'KY',
'postalCode' => '40202',
'countryCode' => 'US'
]
]),
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.farthing.ai/v1/buyer-profiles"
payload := strings.NewReader("{\n \"label\": \"ada-home\",\n \"name\": {\n \"first\": \"Ada\",\n \"last\": \"Lovelace\"\n },\n \"contact\": {\n \"email\": \"ada@example.com\",\n \"phone\": \"+15555550123\"\n },\n \"shipping\": {\n \"addressLines\": [\n \"1 Analytical Way\"\n ],\n \"locality\": \"Louisville\",\n \"administrativeAreaCode\": \"KY\",\n \"postalCode\": \"40202\",\n \"countryCode\": \"US\"\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.farthing.ai/v1/buyer-profiles")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"label\": \"ada-home\",\n \"name\": {\n \"first\": \"Ada\",\n \"last\": \"Lovelace\"\n },\n \"contact\": {\n \"email\": \"ada@example.com\",\n \"phone\": \"+15555550123\"\n },\n \"shipping\": {\n \"addressLines\": [\n \"1 Analytical Way\"\n ],\n \"locality\": \"Louisville\",\n \"administrativeAreaCode\": \"KY\",\n \"postalCode\": \"40202\",\n \"countryCode\": \"US\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.farthing.ai/v1/buyer-profiles")
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 \"label\": \"ada-home\",\n \"name\": {\n \"first\": \"Ada\",\n \"last\": \"Lovelace\"\n },\n \"contact\": {\n \"email\": \"ada@example.com\",\n \"phone\": \"+15555550123\"\n },\n \"shipping\": {\n \"addressLines\": [\n \"1 Analytical Way\"\n ],\n \"locality\": \"Louisville\",\n \"administrativeAreaCode\": \"KY\",\n \"postalCode\": \"40202\",\n \"countryCode\": \"US\"\n }\n}"
response = http.request(request)
puts response.read_body{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"label": "<string>",
"subject": "user_a91f",
"name": {},
"contact": {},
"shipping": {},
"createdAt": "2023-11-07T05:31:56Z"
}Authorizations
Authorization: Bearer ck_test_… or ck_live_…. There is no other auth scheme — no query-string keys, no request signing, no OAuth.
Body
Every field is optional — {} is a valid profile — but the agent can only fill what you gave it.
The top level is strict: an unrecognised field is a 400 with an unrecognized_keys issue, not a field the server drops for you. The field most worth misspelling here is subject, and a 201 carrying an untagged row is an isolation control that failed open on a typo. The nested name, contact and shipping objects are not strict. PATCH is strict in the same way.
Yours, for bookkeeping. Never sent to a merchant.
Your own opaque id for one of your end users. 1 to 200 characters after trimming; never parsed, never validated against anything, and never sent to a merchant. An empty or whitespace-only value is a 400 — a subject that means nothing reads as isolation you do not have.
On a key bound to a subject this is filled in for you: omit it and the row is stamped with the key's subject, name a different one and the request is a 403. On a tenant-wide key it is how a row gets tagged in the first place.
Create-only. A profile cannot be reassigned to another end user afterwards: PATCH with subject is a 400.
1 - 200"user_a91f"
Also used as the cardholder name at the payment step, which is why the card action never asks for one.
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Response
Created. Omitted sub-objects come back as null, not {}.
Your own id for the end user this profile belongs to, or null when it is not tagged to one. Always present — unlike a checkout, which omits the field entirely. Fixed at creation.
"user_a91f"
null when never supplied — not {}.