Stablecoin payouts integration guide

This guide walks through using Latitude’s stablecoin payouts product. You prefund USD into your Latitude account and then provide Latitude with instructions to disperse stablecoins in real-time.

Before you start, make sure you’re familiar with the API basics — authentication, idempotency, webhooks, and prefunding.

Summary

The high-level steps are as follows:

  1. Prerequisites
    • Prefund your Latitude account with USD via wire transfer
    • (Optional) Create a webhook subscription for individual and/or transfer events
  2. Create an individual representing the recipient
  3. Create a transfer with the details of the intended payout
  4. Receive webhooks for transfer and individual lifecycle events

Detailed Steps

Step 0: Prerequisites

a) Prefund your Latitude account

See API basics — Prefunded flows for funding options.

b) (Optional) Create a webhook subscription

Create a webhook subscription to be notified of individual and transfer events. See API basics — Webhooks for details. The relevant event types for this flow are:

  • transfer.completed — sent when a transfer completes successfully
  • transfer.failed — sent when a transfer terminally fails
  • individual.status_changed — sent when an individual’s status changes

Step 1: Create an Individual

Request:

1POST /v1/individuals HTTP/1.1
2Content-Type: application/json
3
4{
5 "given_name": "María",
6 "family_name": "González Hernández",
7 "country": "MX",
8 "product_types": ["global_payouts"],
9 "address": {
10 "line_1": "Av. Paseo de la Reforma 505",
11 "line_2": "Piso 12, Col. Cuauhtémoc",
12 "city": "Ciudad de México",
13 "state": "CDMX",
14 "postal_code": "06500"
15 },
16 "financial_accounts": [
17 {
18 "type": "crypto_wallet",
19 "details": {
20 "address": "0x742d35Cc6634C0532925a3b844Bc9e7595f8fE21",
21 "network": "base"
22 }
23 }
24 ]
25}

Response:

1HTTP/1.1 201 Created
2Content-Type: application/json
3
4{
5 "id": "ind_8b4c3d2e",
6 "status": "pending",
7 "status_details": null,
8 "first_name": "María",
9 "last_name": "González Hernández",
10 "country": "MX",
11 "address": {
12 "line_1": "Av. Paseo de la Reforma 505",
13 "line_2": "Piso 12, Col. Cuauhtémoc",
14 "city": "Ciudad de México",
15 "state": "CDMX",
16 "postal_code": "06500",
17 "country": "MX"
18 },
19 "financial_accounts": [
20 {
21 "id": "fa_9k2m3n4p",
22 "type": "crypto_wallet",
23 "details": {
24 "address": "0x742d35Cc6634C0532925a3b844Bc9e7595f8fE21",
25 "network": "base"
26 },
27 "created_at": "2025-01-30T14:32:00Z",
28 "updated_at": "2025-01-30T14:32:00Z"
29 }
30 ],
31 "product_types": ["global_payouts"],
32 "created_at": "2025-01-30T14:32:00Z",
33 "updated_at": "2025-01-30T14:32:00Z"
34}

Step 2: Create a Transfer

Create a transfer by specifying the payout details directly. You must specify either source_amount (to send a fixed amount) or destination_amount (to have a specific amount arrive). Optionally, you can first create a quote to preview the conversion rate and fees, and then pass the quote_id when creating the transfer.

Request:

1POST /v1/transfers HTTP/1.1
2Content-Type: application/json
3
4{
5 "financial_account_id": "fa_9k2m3n4p",
6 "payout_method": "blockchain_transfer",
7 "source_amount": "100.00",
8 "source_currency": "usd",
9 "destination_currency": "usdc"
10}

Response:

1HTTP/1.1 201 Created
2Content-Type: application/json
3
4{
5 "id": "tr_3d4e5f6a",
6 "client_reference_id": null,
7 "source_amount": "100.00",
8 "source_currency": "usd",
9 "destination_amount": "98.95",
10 "destination_currency": "usdc",
11 "exchange_rate": "1.0000",
12 "recipient_id": "ind_8b4c3d2e",
13 "financial_account_id": "fa_9k2m3n4p",
14 "payout_method": "blockchain_transfer",
15 "status": "processing",
16 "total_fee": "1.05",
17 "fee_currency": "usd",
18 "total_tax": "0.00",
19 "tax_currency": "usd",
20 "net_source_amount": null,
21 "completed_in": null,
22 "failure_reason": null,
23 "settlement_reference_id": null,
24 "created_at": "2025-01-30T14:34:00Z",
25 "updated_at": "2025-01-30T14:34:00Z"
26}

Step 3: Receive Webhooks

a) When an individual’s status changes

1{
2 "event_type": "individual.status_changed",
3 "event_payload": {
4 "id": "ind_8b4c3d2e",
5 "status": "active",
6 "status_details": [],
7 "previous_status": "pending",
8 "updated_at": "2025-01-30T14:35:00Z"
9 }
10}

b) When a transfer is completed

1{
2 "event_type": "transfer.completed",
3 "event_payload": {
4 "id": "tr_3d4e5f6a",
5 "client_reference_id": null,
6 "source_amount": "100.00",
7 "source_currency": "usd",
8 "destination_amount": "98.95",
9 "destination_currency": "usdc",
10 "exchange_rate": "1.0000",
11 "recipient_id": "ind_8b4c3d2e",
12 "financial_account_id": "fa_9k2m3n4p",
13 "payout_method": "blockchain_transfer",
14 "status": "completed",
15 "total_fee": "1.05",
16 "fee_currency": "usd",
17 "total_tax": "0.00",
18 "tax_currency": "usd",
19 "net_source_amount": null,
20 "completed_in": "60",
21 "failure_reason": null,
22 "settlement_reference_id": "0x7a3f8b2c1d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a",
23 "created_at": "2025-01-30T14:34:00Z",
24 "updated_at": "2025-01-30T14:39:30Z"
25 }
26}

c) When a transfer fails

1{
2 "event_type": "transfer.failed",
3 "event_payload": {
4 "id": "tr_3d4e5f6a",
5 "client_reference_id": null,
6 "source_amount": "100.00",
7 "source_currency": "usd",
8 "destination_amount": "98.95",
9 "destination_currency": "usdc",
10 "exchange_rate": "1.0000",
11 "recipient_id": "ind_8b4c3d2e",
12 "financial_account_id": "fa_9k2m3n4p",
13 "payout_method": "blockchain_transfer",
14 "status": "failed",
15 "total_fee": "1.05",
16 "fee_currency": "usd",
17 "total_tax": "0.00",
18 "tax_currency": "usd",
19 "net_source_amount": null,
20 "completed_in": null,
21 "failure_reason": "blockchain_transfer_failed",
22 "settlement_reference_id": null,
23 "created_at": "2025-01-30T14:34:00Z",
24 "updated_at": "2025-01-30T14:39:30Z"
25 }
26}