Transfers
Move MYRT to a recipient wallet on a linked customer's behalf. The flow, the key handling advice and the reasoning are in the transfers guide; this page states the shapes.
Create a transfer
/v1/transfersCreates a transfer and submits it for settlement in the same call, so the key must hold both transfer:create and transfer:execute. Two ceilings apply and are enforced on every request: 50,000 MYRT per transaction and 250,000 MYRT per key per UTC day. Failed and cancelled transfers do not count toward the daily total. A recipient that fails screening is refused with 403 RECIPIENT_NOT_PERMITTED.
Headers
| Header | Required | Value |
|---|---|---|
Authorization | yes | Bearer <key> with transfer:create and transfer:execute |
Idempotency-Key | yes | A UUID you generate per logical operation, at most 255 characters |
Content-Type | yes | application/json |
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
referenceId | string | yes | 8 to 100 characters: letters, digits, dot, underscore, dash, colon. Unique within your integration |
amountMyrt | string | yes | Positive decimal, at most 6 decimal places |
walletAddress | string | yes | EVM address that receives the MYRT |
customerId | string | yes | The account the transfer is debited against, linked to your integration |
chainId | number | no | Defaults to the active chain |
curl -X POST https://sandbox-api.myrt.money/v1/transfers \
-H "Authorization: Bearer $MYRT_API_KEY" \
-H "Idempotency-Key: 9b2d0f6e-3c1a-4e8f-9d7b-5a6c4e2f1b0a" \
-H "Content-Type: application/json" \
-d '{
"referenceId": "acme:transfer:2026-09-10:00031",
"amountMyrt": "250.00",
"walletAddress": "0xAbC0000000000000000000000000000000000001",
"customerId": "cus_9f2a3b4c"
}'import { randomUUID } from "node:crypto";
const res = await fetch("https://sandbox-api.myrt.money/v1/transfers", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.MYRT_API_KEY}`,
"Idempotency-Key": randomUUID(),
"Content-Type": "application/json",
},
body: JSON.stringify({
referenceId: "acme:transfer:2026-09-10:00031",
amountMyrt: "250.00",
walletAddress: "0xAbC0000000000000000000000000000000000001",
customerId: "cus_9f2a3b4c",
}),
});
const order = await res.json();import os, uuid, requests
res = requests.post(
"https://sandbox-api.myrt.money/v1/transfers",
headers={
"Authorization": f"Bearer {os.environ['MYRT_API_KEY']}",
"Idempotency-Key": str(uuid.uuid4()),
},
json={
"referenceId": "acme:transfer:2026-09-10:00031",
"amountMyrt": "250.00",
"walletAddress": "0xAbC0000000000000000000000000000000000001",
"customerId": "cus_9f2a3b4c",
},
timeout=30,
)
order = res.json()Response 201 Created
{
"ok": true,
"referenceId": "acme:transfer:2026-09-10:00031",
"status": "pending",
"phase": "ORDER_CREATED",
"direction": "TRANSFER",
"chainId": 1,
"network": "Ethereum",
"tokenAddress": "0x...",
"walletAddress": "0xAbC0000000000000000000000000000000000001",
"amounts": {
"myr": null,
"myrt": "250.00",
"feeMyr": "0",
"amountRaw": "250000000",
"decimals": 6
},
"blockchain": { "txHash": null, "blockNumber": null },
"timestamps": { "createdAt": "2026-09-10T04:12:33.918Z", "updatedAt": null }
}walletAddress is the recipient. For a transfer, amounts.myrt is the amount moved, amounts.myr is null and amounts.feeMyr is "0". See amounts.
A replay of the same Idempotency-Key and body returns this response again with X-MYRT-Idempotent-Replay: true. Posting a referenceId that already exists returns the existing order.
Errors
| Code | HTTP |
|---|---|
INVALID_JSON | 400 |
IDEMPOTENCY_KEY_REQUIRED | 400 |
INVALID_AMOUNT | 400 |
INVALID_WALLET_ADDRESS | 400 |
INVALID_REFERENCE_ID | 400 |
AMOUNT_NEGATIVE_OR_ZERO | 400 |
TRANSFER_PER_TX_CAP_EXCEEDED | 400 |
TRANSFER_DAILY_CAP_EXCEEDED | 400 |
POLICY_REJECTED | 400 |
RECIPIENT_NOT_PERMITTED | 403 |
SCOPE_DENIED | 403 |
CUSTOMER_NOT_VERIFIED | 403 |
NOT_FOUND | 404 |
IDEMPOTENCY_CONFLICT | 409 |
SETTLEMENT_FAILED | 502 |
TRANSFER_PER_TX_CAP_EXCEEDED and TRANSFER_DAILY_CAP_EXCEEDED carry meta.requestedMyrt, meta.committedTodayMyrt, meta.perTxCapMyrt and meta.dailyCapMyrt. Read the caps from meta rather than hardcoding them; they may be lowered.
See errors for the meaning of each code.
Read a transfer
/v1/transfers/{referenceId}Returns the current state of a transfer you created. An order that is not a transfer, or that another integration created, returns 404 NOT_FOUND, the same as an order that does not exist. A transfer is completed only after the chain's confirmation count; a txHash alone is not final. See order lifecycle.
Path parameters
| Parameter | Type | Notes |
|---|---|---|
referenceId | string | The referenceId you supplied on creation |
curl https://sandbox-api.myrt.money/v1/transfers/acme:transfer:2026-09-10:00031 \
-H "Authorization: Bearer $MYRT_API_KEY"const res = await fetch(
"https://sandbox-api.myrt.money/v1/transfers/acme:transfer:2026-09-10:00031",
{ headers: { Authorization: `Bearer ${process.env.MYRT_API_KEY}` } }
);
const order = await res.json();import os, requests
res = requests.get(
"https://sandbox-api.myrt.money/v1/transfers/acme:transfer:2026-09-10:00031",
headers={"Authorization": f"Bearer {os.environ['MYRT_API_KEY']}"},
timeout=30,
)
order = res.json()Response 200 OK
{
"ok": true,
"referenceId": "acme:transfer:2026-09-10:00031",
"status": "completed",
"phase": "COMPLETED",
"direction": "TRANSFER",
"chainId": 1,
"network": "Ethereum",
"tokenAddress": "0x...",
"walletAddress": "0xAbC0000000000000000000000000000000000001",
"amounts": {
"myr": null,
"myrt": "250.00",
"feeMyr": "0",
"amountRaw": "250000000",
"decimals": 6
},
"blockchain": { "txHash": "0x...", "blockNumber": "20481922" },
"timestamps": { "createdAt": "2026-09-10T04:12:33.918Z", "updatedAt": "2026-09-10T04:19:02.441Z" }
}Errors
| Code | HTTP |
|---|---|
INVALID_REFERENCE_ID | 400 |
NOT_FOUND | 404 |
