|
1
|
--- |
|
2
|
title: "Funding Method — Bind Payment to Procurement Session" |
|
3
|
sidebarTitle: "POST /funding-method" |
|
4
|
description: "Bind a payment method to an active procurement session. Accepts USDC on-chain, card, ACH bank transfer, or ETH wallet. Replaces the deprecated POST /api/payments/route." |
|
5
|
--- |
|
6
|
|
|
7
|
Once a procurement session is ready for payment, this endpoint binds a funding method to it. You specify the method type — USDC, card, bank transfer (ACH), or ETH wallet — and supply method-specific fields. For USDC and ETH wallet payments, include the target blockchain network. For ACH bank transfers, include routing and account details. For ETH wallet, include the `0x` address (optional ENS). ProcureNet validates the combination against the session's state and the buyer's entitlements, then advances the session toward payment processing. This endpoint replaces the deprecated `POST /api/payments/route` — if your integration still uses that path, follow the migration guidance at the bottom of this page. |
|
8
|
|
|
9
|
## Authentication |
|
10
|
|
|
11
|
<Warning> |
|
12
|
This endpoint requires a valid Bearer JWT in the `Authorization` header. Requests without a token, or with an expired or malformed token, receive `401 Unauthorized`. |
|
13
|
</Warning> |
|
14
|
|
|
15
|
``` |
|
16
|
Authorization: Bearer <your_jwt> |
|
17
|
``` |
|
18
|
|
|
19
|
## Path Parameters |
|
20
|
|
|
21
|
<ParamField path="id" type="string" required> |
|
22
|
The session ID returned by `POST /api/v7/orchestrate`. The session must be in a state that accepts a funding method (for example, `pending_payment` or `escrow_accepted`). |
|
23
|
</ParamField> |
|
24
|
|
|
25
|
## Request Body |
|
26
|
|
|
27
|
<ParamField body="method" type="string" required> |
|
28
|
The payment method to bind to this session. Accepted values: |
|
29
|
|
|
30
|
| Value | Description | |
|
31
|
|---|---| |
|
32
|
| `usdc` | On-chain USDC transfer. Requires the `network` field. | |
|
33
|
| `card` | Credit or debit card. Network and ACH fields are ignored. | |
|
34
|
| `bank_transfer` | ACH debit from a US bank account. Requires ACH fields below. Network is ignored. | |
|
35
|
| `eth_wallet` | Native ETH from a buyer wallet. Requires `wallet_address` and `network`. Optional `ens_name`. | |
|
36
|
</ParamField> |
|
37
|
|
|
38
|
<ParamField body="network" type="string"> |
|
39
|
The blockchain network for on-chain funding. Required when `method` is `"usdc"` or `"eth_wallet"`. Ignored for `card` and `bank_transfer`. |
|
40
|
|
|
41
|
Supported values: `base`, `arbitrum`, `polygon`, `ethereum`. |
|
42
|
|
|
43
|
<Tip> |
|
44
|
For USDC, `base` offers the lowest gas fees and is recommended unless your buyer or contract rules require otherwise. For native ETH (`eth_wallet`), default to `ethereum` unless the buyer wallet is L2-native. |
|
45
|
</Tip> |
|
46
|
</ParamField> |
|
47
|
|
|
48
|
### ACH fields (`method: "bank_transfer"`) |
|
49
|
|
|
50
|
When `method` is `"bank_transfer"`, include the following fields. They are ignored for `usdc`, `card`, and `eth_wallet`. |
|
51
|
|
|
52
|
<ParamField body="routing_number" type="string" required> |
|
53
|
ABA routing transit number for the buyer's US bank. Must be exactly **9 digits**. Leading zeros are significant — send as a string, not a number. |
|
54
|
|
|
55
|
Example: `"021000021"` |
|
56
|
</ParamField> |
|
57
|
|
|
58
|
<ParamField body="account_number" type="string" required> |
|
59
|
The buyer's bank account number. Digits only; typically 4–17 characters. Do not include spaces or hyphens. |
|
60
|
|
|
61
|
Example: `"123456789012"` |
|
62
|
</ParamField> |
|
63
|
|
|
64
|
<ParamField body="account_type" type="string" required> |
|
65
|
The type of bank account to debit. Accepted values: |
|
66
|
|
|
67
|
| Value | Description | |
|
68
|
|---|---| |
|
69
|
| `checking` | Checking account | |
|
70
|
| `savings` | Savings account | |
|
71
|
</ParamField> |
|
72
|
|
|
73
|
<ParamField body="account_holder_name" type="string" required> |
|
74
|
Legal name on the bank account, as it appears at the financial institution. Used for ACH authorization matching. Length 2–100 characters. |
|
75
|
|
|
76
|
Example: `"Acme Procurement LLC"` |
|
77
|
</ParamField> |
|
78
|
|
|
79
|
<Info> |
|
80
|
ACH credentials are transmitted over TLS and stored only as needed to originate the debit. Full account numbers are never returned in API responses — only a masked last-four form is echoed. |
|
81
|
</Info> |
|
82
|
|
|
83
|
|
|
84
|
### ETH wallet fields (`method: "eth_wallet"`) |
|
85
|
|
|
86
|
When `method` is `"eth_wallet"`, include the following fields. They are ignored for `usdc`, `card`, and `bank_transfer`. |
|
87
|
|
|
88
|
<ParamField body="wallet_address" type="string" required> |
|
89
|
Buyer EVM wallet address that will fund the session with native ETH. Must be a checksum-compatible hex address: `0x` followed by exactly **40** hexadecimal characters (`/^0x[a-fA-F0-9]{40}$/`). Case may be mixed (EIP-55); the API normalizes to lowercase for storage and returns the submitted casing when valid. |
|
90
|
|
|
91
|
Example: `"0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0"` |
|
92
|
</ParamField> |
|
93
|
|
|
94
|
<ParamField body="ens_name" type="string"> |
|
95
|
Optional ENS name associated with the wallet (for example `"acme.eth"`). Display and verification aid only — settlement always uses `wallet_address`. If both are provided, the resolved ENS address must match `wallet_address` or the request fails with `422`. |
|
96
|
|
|
97
|
Example: `"treasury.acme.eth"` |
|
98
|
</ParamField> |
|
99
|
|
|
100
|
<ParamField body="network" type="string" required> |
|
101
|
Chain for the ETH debit. Same enum as USDC: `base`, `arbitrum`, `polygon`, `ethereum`. Prefer `ethereum` for native mainnet ETH unless the buyer wallet is L2-native. |
|
102
|
</ParamField> |
|
103
|
|
|
104
|
<Info> |
|
105
|
ProcureNet never asks for a private key or seed phrase. The buyer signs or authorizes the transfer in their wallet after the funding method is bound. Only the address (and optional ENS) are stored on the session. |
|
106
|
</Info> |
|
107
|
|
|
108
|
|
|
109
|
### Platform fee (optional) |
|
110
|
|
|
111
|
Optionally attach a platform fee when binding the funding method. Omit these fields to charge no platform fee. |
|
112
|
|
|
113
|
<ParamField body="fee_bps" type="integer"> |
|
114
|
Platform fee in basis points. `100` = **1%** of the funded amount. Typical range `0`–`10000` (0%–100%). When omitted, no platform fee is applied. |
|
115
|
</ParamField> |
|
116
|
|
|
117
|
<ParamField body="fee_recipient" type="string"> |
|
118
|
ETH address that receives the platform fee. Must match `/^0x[a-fA-F0-9]{40}$/`. Defaults to the ProcureNet platform wallet when `fee_bps` is set and this field is omitted: |
|
119
|
|
|
120
|
`0xD0Fb43F2e9b4Dcd4C9FB70DA89385f77086cb778` |
|
121
|
</ParamField> |
|
122
|
|
|
123
|
<ParamField body="fee_asset" type="string"> |
|
124
|
Asset used to settle the platform fee. Accepted values: |
|
125
|
|
|
126
|
| Value | Description | |
|
127
|
|---|---| |
|
128
|
| `eth` | Native ETH | |
|
129
|
| `usdc` | USDC | |
|
130
|
|
|
131
|
On-chain methods (`usdc`, `eth_wallet`) can take the fee on the **same rail** as the funding method (for example USDC fee on a USDC bind, or ETH fee on `eth_wallet`). For `card` and `bank_transfer`, settlement proceeds are routed to `fee_recipient` **later** (off the primary ACH/card rail) — `fee_asset` still records the intended payout asset. |
|
132
|
</ParamField> |
|
133
|
|
|
134
|
<Info> |
|
135
|
When the session amount is already known, the API may echo `fee_bps`, `fee_recipient`, and a computed `fee_amount` in the response. If amount is not yet known, only the fee configuration fields are echoed. |
|
136
|
</Info> |
|
137
|
|
|
138
|
## Request Examples |
|
139
|
|
|
140
|
<CodeGroup> |
|
141
|
|
|
142
|
```typescript USDC on Base |
|
143
|
const sessionId = 'sess_abc123'; |
|
144
|
|
|
145
|
const res = await fetch( |
|
146
|
`https://api.procurenet.io/api/v7/sessions/${sessionId}/funding-method`, |
|
147
|
{ |
|
148
|
method: 'POST', |
|
149
|
headers: { |
|
150
|
'Authorization': 'Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...', |
|
151
|
'Content-Type': 'application/json' |
|
152
|
}, |
|
153
|
body: JSON.stringify({ |
|
154
|
method: 'usdc', |
|
155
|
network: 'base', |
|
156
|
fee_bps: 100, // 1% |
|
157
|
fee_recipient: '0xD0Fb43F2e9b4Dcd4C9FB70DA89385f77086cb778', |
|
158
|
fee_asset: 'usdc' // same rail as funding |
|
159
|
}) |
|
160
|
} |
|
161
|
); |
|
162
|
|
|
163
|
const result = await res.json(); |
|
164
|
``` |
|
165
|
|
|
166
|
```typescript Card Payment |
|
167
|
const sessionId = 'sess_abc123'; |
|
168
|
|
|
169
|
const res = await fetch( |
|
170
|
`https://api.procurenet.io/api/v7/sessions/${sessionId}/funding-method`, |
|
171
|
{ |
|
172
|
method: 'POST', |
|
173
|
headers: { |
|
174
|
'Authorization': 'Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...', |
|
175
|
'Content-Type': 'application/json' |
|
176
|
}, |
|
177
|
body: JSON.stringify({ |
|
178
|
method: 'card', |
|
179
|
fee_bps: 100, |
|
180
|
fee_recipient: '0xD0Fb43F2e9b4Dcd4C9FB70DA89385f77086cb778', |
|
181
|
fee_asset: 'usdc' // card/ACH: proceeds settle to fee_recipient later |
|
182
|
}) |
|
183
|
} |
|
184
|
); |
|
185
|
|
|
186
|
const result = await res.json(); |
|
187
|
``` |
|
188
|
|
|
189
|
```typescript ACH Bank Transfer |
|
190
|
const sessionId = 'sess_abc123'; |
|
191
|
|
|
192
|
const res = await fetch( |
|
193
|
`https://api.procurenet.io/api/v7/sessions/${sessionId}/funding-method`, |
|
194
|
{ |
|
195
|
method: 'POST', |
|
196
|
headers: { |
|
197
|
'Authorization': 'Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...', |
|
198
|
'Content-Type': 'application/json' |
|
199
|
}, |
|
200
|
body: JSON.stringify({ |
|
201
|
method: 'bank_transfer', |
|
202
|
routing_number: '021000021', |
|
203
|
account_number: '123456789012', |
|
204
|
account_type: 'checking', |
|
205
|
account_holder_name: 'Acme Procurement LLC', |
|
206
|
fee_bps: 100, |
|
207
|
fee_recipient: '0xD0Fb43F2e9b4Dcd4C9FB70DA89385f77086cb778', |
|
208
|
fee_asset: 'usdc' |
|
209
|
}) |
|
210
|
} |
|
211
|
); |
|
212
|
|
|
213
|
const result = await res.json(); |
|
214
|
``` |
|
215
|
|
|
216
|
```typescript ETH Wallet |
|
217
|
const sessionId = 'sess_abc123'; |
|
218
|
|
|
219
|
const res = await fetch( |
|
220
|
`https://api.procurenet.io/api/v7/sessions/${sessionId}/funding-method`, |
|
221
|
{ |
|
222
|
method: 'POST', |
|
223
|
headers: { |
|
224
|
'Authorization': 'Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...', |
|
225
|
'Content-Type': 'application/json' |
|
226
|
}, |
|
227
|
body: JSON.stringify({ |
|
228
|
method: 'eth_wallet', |
|
229
|
wallet_address: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0', |
|
230
|
ens_name: 'treasury.acme.eth', // optional |
|
231
|
network: 'ethereum', |
|
232
|
fee_bps: 100, |
|
233
|
fee_recipient: '0xD0Fb43F2e9b4Dcd4C9FB70DA89385f77086cb778', |
|
234
|
fee_asset: 'eth' // same rail as funding |
|
235
|
}) |
|
236
|
} |
|
237
|
); |
|
238
|
|
|
239
|
const result = await res.json(); |
|
240
|
``` |
|
241
|
|
|
242
|
</CodeGroup> |
|
243
|
|
|
244
|
### cURL — ACH |
|
245
|
|
|
246
|
```bash |
|
247
|
curl -X POST \ |
|
248
|
https://api.procurenet.io/api/v7/sessions/sess_abc123/funding-method \ |
|
249
|
-H "Authorization: Bearer $JWT" \ |
|
250
|
-H "Content-Type: application/json" \ |
|
251
|
-d '{ |
|
252
|
"method": "bank_transfer", |
|
253
|
"routing_number": "021000021", |
|
254
|
"account_number": "123456789012", |
|
255
|
"account_type": "checking", |
|
256
|
"account_holder_name": "Acme Procurement LLC", |
|
257
|
"fee_bps": 100, |
|
258
|
"fee_recipient": "0xD0Fb43F2e9b4Dcd4C9FB70DA89385f77086cb778", |
|
259
|
"fee_asset": "usdc" |
|
260
|
}' |
|
261
|
``` |
|
262
|
|
|
263
|
|
|
264
|
### cURL — ETH wallet |
|
265
|
|
|
266
|
```bash |
|
267
|
curl -X POST \ |
|
268
|
https://api.procurenet.io/api/v7/sessions/sess_abc123/funding-method \ |
|
269
|
-H "Authorization: Bearer $JWT" \ |
|
270
|
-H "Content-Type: application/json" \ |
|
271
|
-d '{ |
|
272
|
"method": "eth_wallet", |
|
273
|
"wallet_address": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0", |
|
274
|
"ens_name": "treasury.acme.eth", |
|
275
|
"network": "ethereum", |
|
276
|
"fee_bps": 100, |
|
277
|
"fee_recipient": "0xD0Fb43F2e9b4Dcd4C9FB70DA89385f77086cb778", |
|
278
|
"fee_asset": "eth" |
|
279
|
}' |
|
280
|
``` |
|
281
|
|
|
282
|
## Response Fields |
|
283
|
|
|
284
|
<ResponseField name="session_id" type="string" required> |
|
285
|
Echoes back the session ID. |
|
286
|
</ResponseField> |
|
287
|
|
|
288
|
<ResponseField name="method" type="string" required> |
|
289
|
Confirms the payment method that was bound to the session (`usdc`, `card`, `bank_transfer`, or `eth_wallet`). |
|
290
|
</ResponseField> |
|
291
|
|
|
292
|
<ResponseField name="network" type="string"> |
|
293
|
The blockchain network confirmed for on-chain funding. Present when `method` is `"usdc"` or `"eth_wallet"`. |
|
294
|
</ResponseField> |
|
295
|
|
|
296
|
<ResponseField name="status" type="string" required> |
|
297
|
The session status after the funding method was set. Typically `"payment_processing"` once the session advances. For ACH, status may remain `"payment_processing"` until the debit clears (see `ach_status`). |
|
298
|
</ResponseField> |
|
299
|
|
|
300
|
<ResponseField name="account_type" type="string"> |
|
301
|
Echo of the submitted account type (`checking` or `savings`). Present only when `method` is `"bank_transfer"`. |
|
302
|
</ResponseField> |
|
303
|
|
|
304
|
<ResponseField name="account_holder_name" type="string"> |
|
305
|
Echo of the submitted account holder name. Present only when `method` is `"bank_transfer"`. |
|
306
|
</ResponseField> |
|
307
|
|
|
308
|
<ResponseField name="routing_number_last4" type="string"> |
|
309
|
Last four digits of the ABA routing number. Present only when `method` is `"bank_transfer"`. |
|
310
|
</ResponseField> |
|
311
|
|
|
312
|
<ResponseField name="account_number_last4" type="string"> |
|
313
|
Last four digits of the bank account number. Present only when `method` is `"bank_transfer"`. Full account numbers are never returned. |
|
314
|
</ResponseField> |
|
315
|
|
|
316
|
<ResponseField name="ach_status" type="string"> |
|
317
|
ACH-specific processing state. Present only when `method` is `"bank_transfer"`. |
|
318
|
|
|
319
|
| Value | Description | |
|
320
|
|---|---| |
|
321
|
| `pending` | Debit originated; awaiting bank confirmation. | |
|
322
|
| `submitted` | Sent to the ACH network. | |
|
323
|
| `settled` | Funds cleared. | |
|
324
|
| `returned` | Debit returned (insufficient funds, invalid account, etc.). | |
|
325
|
</ResponseField> |
|
326
|
|
|
327
|
|
|
328
|
<ResponseField name="wallet_address" type="string"> |
|
329
|
Echo of the submitted wallet address. Present only when `method` is `"eth_wallet"`. |
|
330
|
</ResponseField> |
|
331
|
|
|
332
|
<ResponseField name="wallet_address_short" type="string"> |
|
333
|
Short display form (`0x` + first 4 + `…` + last 4). Present only when `method` is `"eth_wallet"`. |
|
334
|
</ResponseField> |
|
335
|
|
|
336
|
<ResponseField name="ens_name" type="string"> |
|
337
|
Echo of the submitted ENS name when provided. Present only when `method` is `"eth_wallet"` and `ens_name` was sent. |
|
338
|
</ResponseField> |
|
339
|
|
|
340
|
|
|
341
|
<ResponseField name="fee_bps" type="integer"> |
|
342
|
Echo of the submitted platform fee in basis points when a fee was configured. |
|
343
|
</ResponseField> |
|
344
|
|
|
345
|
<ResponseField name="fee_recipient" type="string"> |
|
346
|
Echo of the fee recipient address (submitted or platform default). |
|
347
|
</ResponseField> |
|
348
|
|
|
349
|
<ResponseField name="fee_asset" type="string"> |
|
350
|
Echo of the fee asset (`eth` or `usdc`) when provided. |
|
351
|
</ResponseField> |
|
352
|
|
|
353
|
<ResponseField name="fee_amount" type="string"> |
|
354
|
Computed fee amount when the session amount is known (string decimal). Omitted when amount is not yet determined. |
|
355
|
</ResponseField> |
|
356
|
|
|
357
|
## Response Examples |
|
358
|
|
|
359
|
<CodeGroup> |
|
360
|
|
|
361
|
```json USDC |
|
362
|
{ |
|
363
|
"session_id": "sess_abc123", |
|
364
|
"method": "usdc", |
|
365
|
"network": "base", |
|
366
|
"status": "payment_processing", |
|
367
|
"fee_bps": 100, |
|
368
|
"fee_recipient": "0xD0Fb43F2e9b4Dcd4C9FB70DA89385f77086cb778", |
|
369
|
"fee_asset": "usdc", |
|
370
|
"fee_amount": "2.50" |
|
371
|
} |
|
372
|
``` |
|
373
|
|
|
374
|
```json Card |
|
375
|
{ |
|
376
|
"session_id": "sess_abc123", |
|
377
|
"method": "card", |
|
378
|
"status": "payment_processing", |
|
379
|
"fee_bps": 100, |
|
380
|
"fee_recipient": "0xD0Fb43F2e9b4Dcd4C9FB70DA89385f77086cb778", |
|
381
|
"fee_asset": "usdc" |
|
382
|
} |
|
383
|
``` |
|
384
|
|
|
385
|
```json ACH Bank Transfer |
|
386
|
{ |
|
387
|
"session_id": "sess_abc123", |
|
388
|
"method": "bank_transfer", |
|
389
|
"status": "payment_processing", |
|
390
|
"account_type": "checking", |
|
391
|
"account_holder_name": "Acme Procurement LLC", |
|
392
|
"routing_number_last4": "0021", |
|
393
|
"account_number_last4": "9012", |
|
394
|
"ach_status": "pending", |
|
395
|
"fee_bps": 100, |
|
396
|
"fee_recipient": "0xD0Fb43F2e9b4Dcd4C9FB70DA89385f77086cb778", |
|
397
|
"fee_asset": "usdc" |
|
398
|
} |
|
399
|
``` |
|
400
|
|
|
401
|
```json ETH Wallet |
|
402
|
{ |
|
403
|
"session_id": "sess_abc123", |
|
404
|
"method": "eth_wallet", |
|
405
|
"network": "ethereum", |
|
406
|
"status": "payment_processing", |
|
407
|
"wallet_address": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0", |
|
408
|
"wallet_address_short": "0x742d…bEb0", |
|
409
|
"ens_name": "treasury.acme.eth", |
|
410
|
"fee_bps": 100, |
|
411
|
"fee_recipient": "0xD0Fb43F2e9b4Dcd4C9FB70DA89385f77086cb778", |
|
412
|
"fee_asset": "eth", |
|
413
|
"fee_amount": "0.0025" |
|
414
|
} |
|
415
|
``` |
|
416
|
|
|
417
|
</CodeGroup> |
|
418
|
|
|
419
|
## ACH Validation Rules |
|
420
|
|
|
421
|
| Field | Rule | |
|
422
|
|---|---| |
|
423
|
| `routing_number` | Exactly 9 digits (`/^\d{9}$/`). Must pass the ABA check-digit algorithm. | |
|
424
|
| `account_number` | 4–17 digits (`/^\d{4,17}$/`). | |
|
425
|
| `account_type` | One of `checking`, `savings`. | |
|
426
|
| `account_holder_name` | 2–100 characters after trim; letters, spaces, hyphens, periods, and apostrophes allowed. | |
|
427
|
|
|
428
|
<Warning> |
|
429
|
Do not send routing or account numbers as JSON numbers. Leading zeros in ABA routing numbers are significant; always use strings. |
|
430
|
</Warning> |
|
431
|
|
|
432
|
|
|
433
|
## ETH Wallet Validation Rules |
|
434
|
|
|
435
|
| Field | Rule | |
|
436
|
|---|---| |
|
437
|
| `wallet_address` | Required. Must match `/^0x[a-fA-F0-9]{40}$/`. Reject all-zero address (`0x` + 40 zeros). | |
|
438
|
| `ens_name` | Optional. If present: 3–255 chars, valid ENS-like label (letters, digits, hyphens, dots), typically ending in `.eth`. | |
|
439
|
| `network` | Required. One of `base`, `arbitrum`, `polygon`, `ethereum`. | |
|
440
|
|
|
441
|
<Warning> |
|
442
|
Never collect or transmit private keys, seed phrases, or wallet passwords through this endpoint. Only the public address (and optional ENS) belong in the request body. |
|
443
|
</Warning> |
|
444
|
|
|
445
|
|
|
446
|
## Platform Fee Validation Rules |
|
447
|
|
|
448
|
| Field | Rule | |
|
449
|
|---|---| |
|
450
|
| `fee_bps` | Optional integer. When set: `0`–`10000`. `100` = 1%. | |
|
451
|
| `fee_recipient` | Optional. When set: `/^0x[a-fA-F0-9]{40}$/`, not all-zero. Defaults to `0xD0Fb43F2e9b4Dcd4C9FB70DA89385f77086cb778` when `fee_bps` is set and recipient is omitted. | |
|
452
|
| `fee_asset` | Optional. One of `eth`, `usdc`. On-chain methods may settle on the same rail; card/ACH route proceeds to `fee_recipient` later. | |
|
453
|
|
|
454
|
## Supported Networks (USDC & ETH wallet) |
|
455
|
|
|
456
|
<CardGroup cols={2}> |
|
457
|
<Card title="Base" icon="circle-check"> |
|
458
|
Lowest fees. Recommended for most USDC transactions. |
|
459
|
</Card> |
|
460
|
<Card title="Arbitrum" icon="circle-check"> |
|
461
|
Low fees, high throughput. Good alternative to Base. |
|
462
|
</Card> |
|
463
|
<Card title="Polygon" icon="circle-check"> |
|
464
|
Widely supported. Use when buyer wallets are Polygon-native. |
|
465
|
</Card> |
|
466
|
<Card title="Ethereum" icon="circle-check"> |
|
467
|
Highest security and liquidity. Higher gas fees apply. |
|
468
|
</Card> |
|
469
|
</CardGroup> |
|
470
|
|
|
471
|
## Migration from POST /api/payments/route |
|
472
|
|
|
473
|
<Note> |
|
474
|
`POST /api/payments/route` is **deprecated** and will be removed in a future release. Migrate all integrations to the v7 session flow. |
|
475
|
</Note> |
|
476
|
|
|
477
|
Replace your existing single-call payment routing with the two-step v7 session pattern: |
|
478
|
|
|
479
|
<Steps> |
|
480
|
<Step title="Start an orchestration session"> |
|
481
|
Replace your call to `POST /api/payments/route` with a call to `POST /api/v7/orchestrate`. Pass your transaction amount, currency, and any buyer hints. |
|
482
|
|
|
483
|
```typescript |
|
484
|
// Before (deprecated) |
|
485
|
await fetch('/api/payments/route', { |
|
486
|
method: 'POST', |
|
487
|
body: JSON.stringify({ amount: 500, currency: 'USD', paymentMethod: 'usdc' }) |
|
488
|
}); |
|
489
|
|
|
490
|
// After |
|
491
|
const session = await fetch('/api/v7/orchestrate', { |
|
492
|
method: 'POST', |
|
493
|
body: JSON.stringify({ amount: 500, currency: 'USD', hints: { email: 'buyer@example.com' } }) |
|
494
|
}).then(r => r.json()); |
|
495
|
``` |
|
496
|
</Step> |
|
497
|
<Step title="Set the funding method on the session"> |
|
498
|
Take the `session_id` from the orchestrate response and call this endpoint to bind your payment method. |
|
499
|
|
|
500
|
```typescript |
|
501
|
// USDC |
|
502
|
await fetch(`/api/v7/sessions/${session.session_id}/funding-method`, { |
|
503
|
method: 'POST', |
|
504
|
headers: { 'Authorization': `Bearer ${jwt}` }, |
|
505
|
body: JSON.stringify({ |
|
506
|
method: 'usdc', |
|
507
|
network: 'base', |
|
508
|
fee_bps: 100, |
|
509
|
fee_recipient: '0xD0Fb43F2e9b4Dcd4C9FB70DA89385f77086cb778', |
|
510
|
fee_asset: 'usdc' |
|
511
|
}) |
|
512
|
}); |
|
513
|
|
|
514
|
// ACH |
|
515
|
await fetch(`/api/v7/sessions/${session.session_id}/funding-method`, { |
|
516
|
method: 'POST', |
|
517
|
headers: { 'Authorization': `Bearer ${jwt}` }, |
|
518
|
body: JSON.stringify({ |
|
519
|
method: 'bank_transfer', |
|
520
|
routing_number: '021000021', |
|
521
|
account_number: '123456789012', |
|
522
|
account_type: 'checking', |
|
523
|
account_holder_name: 'Acme Procurement LLC', |
|
524
|
fee_bps: 100, |
|
525
|
fee_recipient: '0xD0Fb43F2e9b4Dcd4C9FB70DA89385f77086cb778', |
|
526
|
fee_asset: 'usdc' |
|
527
|
}) |
|
528
|
}); |
|
529
|
|
|
530
|
// ETH wallet |
|
531
|
await fetch(`/api/v7/sessions/${session.session_id}/funding-method`, { |
|
532
|
method: 'POST', |
|
533
|
headers: { 'Authorization': `Bearer ${jwt}` }, |
|
534
|
body: JSON.stringify({ |
|
535
|
method: 'eth_wallet', |
|
536
|
wallet_address: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0', |
|
537
|
network: 'ethereum', |
|
538
|
fee_bps: 100, |
|
539
|
fee_recipient: '0xD0Fb43F2e9b4Dcd4C9FB70DA89385f77086cb778', |
|
540
|
fee_asset: 'eth' |
|
541
|
}) |
|
542
|
}); |
|
543
|
``` |
|
544
|
</Step> |
|
545
|
</Steps> |
|
546
|
|
|
547
|
## Error Codes |
|
548
|
|
|
549
|
| HTTP Status | Description | |
|
550
|
|---|---| |
|
551
|
| `400 Bad Request` | Missing required fields; unrecognized `method`; `method` is `"usdc"` or `"eth_wallet"` but `network` is absent or invalid; `method` is `"bank_transfer"` with invalid ACH fields; or `method` is `"eth_wallet"` with an invalid `wallet_address` / `ens_name`; or invalid `fee_bps` / `fee_recipient` / `fee_asset`. | |
|
552
|
| `401 Unauthorized` | Missing, expired, or invalid Bearer JWT. | |
|
553
|
| `403 Forbidden` | The session state does not permit setting a funding method at this point (for example, escrow acceptance is still required). | |
|
554
|
| `404 Not Found` | No session exists for the provided `id`. | |
|
555
|
| `409 Conflict` | A funding method is already set for this session. Transition to a new session if you need to change it. | |
|
556
|
| `410 Gone` | The session has expired. Start a new session with `POST /api/v7/orchestrate`. | |
|
557
|
| `422 Unprocessable Entity` | ACH details failed bank-side pre-validation (for example, routing number not found in the ABA directory); or ENS name does not resolve to the submitted `wallet_address`. | |
|
558
|
|
|
559
|
### ACH-specific error body example |
|
560
|
|
|
561
|
```json |
|
562
|
{ |
|
563
|
"error": { |
|
564
|
"code": "invalid_routing_number", |
|
565
|
"message": "routing_number must be a valid 9-digit ABA number", |
|
566
|
"field": "routing_number" |
|
567
|
} |
|
568
|
} |
|
569
|
``` |
|
570
|
|
|
571
|
Common ACH field error codes: `invalid_routing_number`, `invalid_account_number`, `invalid_account_type`, `invalid_account_holder_name`, `missing_ach_fields`. |
|
572
|
|
|
573
|
### ETH wallet-specific error body example |
|
574
|
|
|
575
|
```json |
|
576
|
{ |
|
577
|
"error": { |
|
578
|
"code": "invalid_wallet_address", |
|
579
|
"message": "wallet_address must be 0x followed by 40 hex characters", |
|
580
|
"field": "wallet_address" |
|
581
|
} |
|
582
|
} |
|
583
|
``` |
|
584
|
|
|
585
|
Common ETH wallet field error codes: `invalid_wallet_address`, `invalid_ens_name`, `ens_address_mismatch`, `missing_eth_wallet_fields`, `invalid_network`. |
|
586
|
|