curl --request POST \
--url https://aropay.aro.media/api/v1/transfer/letter \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"walletId": "ckwlt0001abcd",
"amount": "50",
"recipient": {
"name": "Jane Doe",
"address": {
"line1": "12 Adeola Odeku Street",
"line2": "Victoria Island",
"landmark": "Opposite Eko Hotel",
"city": "Lagos",
"region": "LA",
"country": "NG"
}
}
}
'const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
walletId: 'ckwlt0001abcd',
amount: '50',
recipient: {
name: 'Jane Doe',
address: {
line1: '12 Adeola Odeku Street',
line2: 'Victoria Island',
landmark: 'Opposite Eko Hotel',
city: 'Lagos',
region: 'LA',
country: 'NG'
}
}
})
};
fetch('https://aropay.aro.media/api/v1/transfer/letter', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://aropay.aro.media/api/v1/transfer/letter"
payload = {
"walletId": "ckwlt0001abcd",
"amount": "50",
"recipient": {
"name": "Jane Doe",
"address": {
"line1": "12 Adeola Odeku Street",
"line2": "Victoria Island",
"landmark": "Opposite Eko Hotel",
"city": "Lagos",
"region": "LA",
"country": "NG"
}
}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)Create letter
Turn a private cAROUSD transfer into a mailable letter. Escrows
amount from a custodial wallet into the Aro Mail vault (a
confidentialTransfer to the platform operator) and returns the
letter with its one-time claimCode, the claimUrl the QR encodes
(https://<aropay-host>/claim#<code>, code in the URL fragment), and
the pdfUrl of the printable page.
Defaults depend on the destination: domestic letters (destination =
the deployment’s home country, US by default) are visible and
expire in 90 days; international letters are sealed and expire in
45 days. Addresses follow the destination’s rules (US: two-letter
state, ZIP or ZIP+4, 64-character lines; elsewhere region or
postal is required). Amounts above the per-letter cap return
400 invalid_amount; too many letters in flight return
429 letter_velocity_limit.
Blocks up to ~20 s for the escrow receipt. A letter returned as
DRAFT with a PENDING escrow leg becomes ESCROWED on a later read
once the receipt lands and the encrypted amount is verified; a
reverted or clamped escrow becomes FAILED with nothing moved. If the
escrow was broadcast but the bookkeeping after it failed, the call
returns 502 escrow_unsettled instead of the letter: the letter
exists as DRAFT (find it in GET /transfer/letter), value has left
the wallet, and reconciliation finishes it on the next read. Do not
create it again.
claimCode and claimUrl are returned only here and on
GET /transfer/letter/{id}, only to the owner, and only while the
letter is not terminal. Anyone holding the code can claim once.
curl --request POST \
--url https://aropay.aro.media/api/v1/transfer/letter \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"walletId": "ckwlt0001abcd",
"amount": "50",
"recipient": {
"name": "Jane Doe",
"address": {
"line1": "12 Adeola Odeku Street",
"line2": "Victoria Island",
"landmark": "Opposite Eko Hotel",
"city": "Lagos",
"region": "LA",
"country": "NG"
}
}
}
'const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
walletId: 'ckwlt0001abcd',
amount: '50',
recipient: {
name: 'Jane Doe',
address: {
line1: '12 Adeola Odeku Street',
line2: 'Victoria Island',
landmark: 'Opposite Eko Hotel',
city: 'Lagos',
region: 'LA',
country: 'NG'
}
}
})
};
fetch('https://aropay.aro.media/api/v1/transfer/letter', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://aropay.aro.media/api/v1/transfer/letter"
payload = {
"walletId": "ckwlt0001abcd",
"amount": "50",
"recipient": {
"name": "Jane Doe",
"address": {
"line1": "12 Adeola Odeku Street",
"line2": "Victoria Island",
"landmark": "Opposite Eko Hotel",
"city": "Lagos",
"region": "LA",
"country": "NG"
}
}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)Authorizations
AroPay API key, sent as Authorization: Bearer aro_sk_…. Created in
the dashboard under Settings → API keys. Takes precedence over a
session cookie when both are present.
Body
Sending wallet; must be custodial and hold enough cAROUSD.
Decimal string in human units, up to the deployment's per-letter cap (default 10,000).
"50"
Show child attributes
Show child attributes
Optional note printed on the letter (hidden from the public preview for sealed letters).
200Defaults to visible for domestic letters and sealed for international ones.
sealed, visible Defaults to 90 (domestic) or 45 (international). Unclaimed letters refund the sender at expiry.
1 <= x <= 180