|
1
|
--- |
|
2
|
title: "Integrate ProcureNet Checkout into Your Application" |
|
3
|
sidebarTitle: "Integrate Checkout" |
|
4
|
description: "Embed ProcureNet's AI-orchestrated checkout flow into your app — from collecting buyer signals to advancing through session states." |
|
5
|
--- |
|
6
|
|
|
7
|
ProcureNet's checkout orchestration flow starts the moment you send buyer signals to the session API. The platform scores those signals using the Wallet Confidence Score (WCS) engine, selects the right transport layer, and returns a session your frontend connects to in real time. This guide walks you through every step, from collecting buyer hints to advancing the session to a completed state. |
|
8
|
|
|
9
|
<Steps> |
|
10
|
|
|
11
|
### Collect Buyer Signals |
|
12
|
|
|
13
|
Before starting a session, gather the buyer signals you have available. ProcureNet's WCS engine weights each signal and assigns a score out of 200. The higher the score, the richer the prefill data you get and the more optimized the transport. |
|
14
|
|
|
15
|
<CardGroup cols={2}> |
|
16
|
<Card title="customerId" icon="fingerprint"> |
|
17
|
**100 pts** — Your internal customer identifier. The single highest-value signal. Always pass this when the buyer is authenticated. |
|
18
|
</Card> |
|
19
|
<Card title="email" icon="envelope"> |
|
20
|
**40 pts** — Buyer's email address. Optional but strongly recommended for guest or partially-identified buyers. |
|
21
|
</Card> |
|
22
|
<Card title="phone" icon="phone"> |
|
23
|
**40 pts** — Buyer's phone number. Combines with email to push partial sessions closer to the resolved threshold. |
|
24
|
</Card> |
|
25
|
<Card title="deviceId" icon="mobile"> |
|
26
|
**20 pts** — A stable device fingerprint. Optional, but it can be the deciding factor for crossing key score thresholds. |
|
27
|
</Card> |
|
28
|
</CardGroup> |
|
29
|
|
|
30
|
The WCS engine uses these scores to classify the session into one of three modes: |
|
31
|
|
|
32
|
| Score Range | Mode | Transport | |
|
33
|
|---|---|---| |
|
34
|
| ≥ 100 | `resolved` | SSE | |
|
35
|
| 40 – 99 | `partial` | WebSocket | |
|
36
|
| < 40 | `anonymous` | WebSocket | |
|
37
|
|
|
38
|
<Tip> |
|
39
|
Pass `deviceId` alongside `email` or `phone` to reach a WCS of 100 even without a `customerId`. A score of 100 unlocks the `resolved` mode and SSE transport — which enables full prefill. You can also combine all four signals for a maximum score of 200. |
|
40
|
</Tip> |
|
41
|
|
|
42
|
### Start the Orchestration Session |
|
43
|
|
|
44
|
Call `POST /api/v7/orchestrate` with your buyer hints and transaction details. This endpoint does not require authentication — include whatever buyer signals you have available. The response includes the `session_id`, WCS score, resolved mode, and the transport your client should connect to. |
|
45
|
|
|
46
|
```typescript |
|
47
|
const res = await fetch('https://api.procurenet.io/api/v7/orchestrate', { |
|
48
|
method: 'POST', |
|
49
|
headers: { |
|
50
|
'Content-Type': 'application/json' |
|
51
|
}, |
|
52
|
body: JSON.stringify({ |
|
53
|
amount: 250.00, |
|
54
|
currency: 'USD', |
|
55
|
hints: { |
|
56
|
customerId: 'cust_123', |
|
57
|
email: 'buyer@example.com' |
|
58
|
} |
|
59
|
}) |
|
60
|
}); |
|
61
|
|
|
62
|
const { session_id, wcs_score, mode, transport } = await res.json(); |
|
63
|
``` |
|
64
|
|
|
65
|
Store `session_id` — every subsequent API call in this checkout flow requires it. |
|
66
|
|
|
67
|
### Connect to the Session Stream |
|
68
|
|
|
69
|
Use the `transport` value from the previous response to open the appropriate real-time connection to your session. |
|
70
|
|
|
71
|
<Tabs> |
|
72
|
<Tab title="SSE (resolved mode)"> |
|
73
|
Use SSE when `transport` is `"sse"`. This is the most reliable transport for fully-identified buyers. |
|
74
|
|
|
75
|
```typescript |
|
76
|
const eventSource = new EventSource( |
|
77
|
`https://api.procurenet.io/api/v7/sessions/${session_id}/stream`, |
|
78
|
{ withCredentials: true } |
|
79
|
); |
|
80
|
|
|
81
|
eventSource.onmessage = (event) => { |
|
82
|
const data = JSON.parse(event.data); |
|
83
|
console.log('Session state:', data.state); |
|
84
|
}; |
|
85
|
``` |
|
86
|
</Tab> |
|
87
|
<Tab title="WebSocket (partial / anonymous)"> |
|
88
|
Use WebSocket when `transport` is `"websocket"`. This handles partial and anonymous sessions. |
|
89
|
|
|
90
|
```typescript |
|
91
|
const ws = new WebSocket( |
|
92
|
`wss://api.procurenet.io/api/v7/sessions/${session_id}/stream` |
|
93
|
); |
|
94
|
|
|
95
|
ws.onmessage = (event) => { |
|
96
|
const data = JSON.parse(event.data); |
|
97
|
console.log('Session state:', data.state); |
|
98
|
}; |
|
99
|
``` |
|
100
|
</Tab> |
|
101
|
</Tabs> |
|
102
|
|
|
103
|
### Handle Prefill for Resolved Sessions |
|
104
|
|
|
105
|
If `mode` is `"resolved"` (WCS ≥ 100), call `GET /api/v7/sessions/{id}/prefill` to retrieve stored buyer data and pre-populate your checkout form. This endpoint requires a Bearer JWT and is only available for resolved sessions. |
|
106
|
|
|
107
|
```typescript |
|
108
|
const prefillRes = await fetch( |
|
109
|
`https://api.procurenet.io/api/v7/sessions/${session_id}/prefill`, |
|
110
|
{ |
|
111
|
headers: { |
|
112
|
'Authorization': `Bearer ${token}` |
|
113
|
} |
|
114
|
} |
|
115
|
); |
|
116
|
|
|
117
|
const prefillData = await prefillRes.json(); |
|
118
|
// prefillData contains address, payment method hints, and buyer profile fields |
|
119
|
``` |
|
120
|
|
|
121
|
<Note> |
|
122
|
Calling `/prefill` on a `partial` or `anonymous` session returns a `403`. Always guard this call with a `mode === 'resolved'` check. |
|
123
|
</Note> |
|
124
|
|
|
125
|
### Set the Funding Method |
|
126
|
|
|
127
|
Once the buyer has selected a payment method, register it against the session by calling `POST /api/v7/sessions/{id}/funding-method`. This endpoint requires a Bearer JWT. Supported methods are `usdc` (with `network`), `card`, `bank_transfer` (ACH), and `eth_wallet` (wallet address + network; optional ENS). |
|
128
|
|
|
129
|
Optionally include a **platform fee** on the bind: `fee_bps` (`100` = 1%), `fee_recipient` (ETH address; defaults to `0xD0Fb43F2e9b4Dcd4C9FB70DA89385f77086cb778`), and `fee_asset` (`eth` | `usdc`). On-chain methods can take the fee on the same rail; card/ACH settle proceeds to `fee_recipient` later. When amount is known, the response may echo `fee_bps`, `fee_recipient`, and `fee_amount`. |
|
130
|
|
|
131
|
See [POST /funding-method](/api/sessions-funding-method) for the full field reference. A static funding-method picker demo lives at `examples/checkout-funding-picker/` in the docs repo. |
|
132
|
|
|
133
|
<Tabs> |
|
134
|
<Tab title="USDC"> |
|
135
|
```typescript |
|
136
|
const fundingRes = await fetch( |
|
137
|
`https://api.procurenet.io/api/v7/sessions/${session_id}/funding-method`, |
|
138
|
{ |
|
139
|
method: 'POST', |
|
140
|
headers: { |
|
141
|
'Content-Type': 'application/json', |
|
142
|
'Authorization': `Bearer ${token}` |
|
143
|
}, |
|
144
|
body: JSON.stringify({ |
|
145
|
method: 'usdc', |
|
146
|
network: 'base', // base | arbitrum | polygon | ethereum |
|
147
|
fee_bps: 100, // 1% |
|
148
|
fee_recipient: '0xD0Fb43F2e9b4Dcd4C9FB70DA89385f77086cb778', |
|
149
|
fee_asset: 'usdc' |
|
150
|
}) |
|
151
|
} |
|
152
|
); |
|
153
|
``` |
|
154
|
</Tab> |
|
155
|
<Tab title="Card"> |
|
156
|
```typescript |
|
157
|
const fundingRes = await fetch( |
|
158
|
`https://api.procurenet.io/api/v7/sessions/${session_id}/funding-method`, |
|
159
|
{ |
|
160
|
method: 'POST', |
|
161
|
headers: { |
|
162
|
'Content-Type': 'application/json', |
|
163
|
'Authorization': `Bearer ${token}` |
|
164
|
}, |
|
165
|
body: JSON.stringify({ |
|
166
|
method: 'card', |
|
167
|
fee_bps: 100, |
|
168
|
fee_recipient: '0xD0Fb43F2e9b4Dcd4C9FB70DA89385f77086cb778', |
|
169
|
fee_asset: 'usdc' // card/ACH: proceeds to fee_recipient later |
|
170
|
}) |
|
171
|
} |
|
172
|
); |
|
173
|
``` |
|
174
|
</Tab> |
|
175
|
<Tab title="ACH (bank_transfer)"> |
|
176
|
```typescript |
|
177
|
const fundingRes = await fetch( |
|
178
|
`https://api.procurenet.io/api/v7/sessions/${session_id}/funding-method`, |
|
179
|
{ |
|
180
|
method: 'POST', |
|
181
|
headers: { |
|
182
|
'Content-Type': 'application/json', |
|
183
|
'Authorization': `Bearer ${token}` |
|
184
|
}, |
|
185
|
body: JSON.stringify({ |
|
186
|
method: 'bank_transfer', |
|
187
|
routing_number: '021000021', // ABA, 9 digits (string) |
|
188
|
account_number: '123456789012', |
|
189
|
account_type: 'checking', // checking | savings |
|
190
|
account_holder_name: 'Acme Procurement LLC', |
|
191
|
fee_bps: 100, |
|
192
|
fee_recipient: '0xD0Fb43F2e9b4Dcd4C9FB70DA89385f77086cb778', |
|
193
|
fee_asset: 'usdc' |
|
194
|
}) |
|
195
|
} |
|
196
|
); |
|
197
|
``` |
|
198
|
|
|
199
|
<Note> |
|
200
|
Always send `routing_number` and `account_number` as strings so leading zeros are preserved. Full account numbers are never returned in responses — only `routing_number_last4` and `account_number_last4`. |
|
201
|
</Note> |
|
202
|
</Tab> |
|
203
|
<Tab title="ETH wallet (eth_wallet)"> |
|
204
|
```typescript |
|
205
|
const fundingRes = await fetch( |
|
206
|
`https://api.procurenet.io/api/v7/sessions/${session_id}/funding-method`, |
|
207
|
{ |
|
208
|
method: 'POST', |
|
209
|
headers: { |
|
210
|
'Content-Type': 'application/json', |
|
211
|
'Authorization': `Bearer ${token}` |
|
212
|
}, |
|
213
|
body: JSON.stringify({ |
|
214
|
method: 'eth_wallet', |
|
215
|
wallet_address: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0', |
|
216
|
ens_name: 'treasury.acme.eth', // optional |
|
217
|
network: 'ethereum', // ethereum | base | arbitrum | polygon |
|
218
|
fee_bps: 100, |
|
219
|
fee_recipient: '0xD0Fb43F2e9b4Dcd4C9FB70DA89385f77086cb778', |
|
220
|
fee_asset: 'eth' |
|
221
|
}) |
|
222
|
} |
|
223
|
); |
|
224
|
``` |
|
225
|
|
|
226
|
<Note> |
|
227
|
`wallet_address` must be `0x` + 40 hex characters. Never send private keys. Settlement is authorized in the buyer wallet after the method is bound. |
|
228
|
</Note> |
|
229
|
</Tab> |
|
230
|
</Tabs> |
|
231
|
|
|
232
|
### Advance Through Session States |
|
233
|
|
|
234
|
Call `POST /api/v7/sessions/{id}/transition` to move the session forward through ProcureNet's state machine. Transitions are event-driven — pass the target event name to advance. This endpoint requires a Bearer JWT. |
|
235
|
|
|
236
|
```typescript |
|
237
|
const transitionRes = await fetch( |
|
238
|
`https://api.procurenet.io/api/v7/sessions/${session_id}/transition`, |
|
239
|
{ |
|
240
|
method: 'POST', |
|
241
|
headers: { |
|
242
|
'Content-Type': 'application/json', |
|
243
|
'Authorization': `Bearer ${token}` |
|
244
|
}, |
|
245
|
body: JSON.stringify({ event: 'confirm' }) |
|
246
|
} |
|
247
|
); |
|
248
|
|
|
249
|
const { state } = await transitionRes.json(); |
|
250
|
console.log('New session state:', state); |
|
251
|
``` |
|
252
|
|
|
253
|
Listen on your stream connection for real-time state change events alongside explicit transition calls. |
|
254
|
|
|
255
|
</Steps> |
|
256
|
|
|
257
|
## Migrating from the Legacy Payments Route |
|
258
|
|
|
259
|
<Warning> |
|
260
|
`POST /api/payments/route` is deprecated and will be removed in a future release. Migrate to `POST /api/v7/orchestrate` as soon as possible to gain WCS scoring, session streaming, and prefill support. |
|
261
|
</Warning> |
|
262
|
|
|
263
|
The legacy `POST /api/payments/route` endpoint does not support WCS scoring, session streaming, or prefill. To migrate: |
|
264
|
|
|
265
|
1. Replace calls to `/api/payments/route` with `POST /api/v7/orchestrate`. |
|
266
|
2. Update your response handling to read `session_id`, `wcs_score`, `mode`, and `transport` from the new response shape. |
|
267
|
3. Connect to the session stream using the transport returned in step 2. |
|
268
|
4. Use `/funding-method` and `/transition` to replace any inline payment routing logic you had in the old flow. |