@mindtdilly / Omnipay-5 / commits / 51ed0ad

docs: generate ProcureNet customer documentation

mintlify[bot] committed Sep 10, 2026 at 11:45 UTC 51ed0adfbe776f26cdec03b66a44f02b2e35a6e2
26 files changed +3364 -100
.atlas-analysis.json new
+104
@@ -0,0 +1,104 @@
1 +{
2 + "projectType": "saas",
3 + "projectName": "ProcureNet",
4 + "projectDescription": "An AI-powered procurement and checkout orchestration platform that routes buyer sessions via a Wallet Confidence Score, manages crypto (USDC) settlement for field evaluations, and coordinates a distributed AI agent swarm for end-to-end procurement workflows.",
5 + "theme": "luma",
6 + "primaryColor": "#6C47FF",
7 + "lightColor": "#EDE9FF",
8 + "darkColor": "#3B1FA8",
9 + "navigation": {
10 + "tabs": [
11 + {
12 + "tab": "Documentation",
13 + "groups": [
14 + {
15 + "group": "Get Started",
16 + "pages": [
17 + "introduction",
18 + "quickstart",
19 + "authentication"
20 + ]
21 + },
22 + {
23 + "group": "Core Concepts",
24 + "pages": [
25 + "concepts/wallet-confidence-score",
26 + "concepts/session-lifecycle",
27 + "concepts/orchestration-modes",
28 + "concepts/payment-settlement"
29 + ]
30 + },
31 + {
32 + "group": "Guides",
33 + "pages": [
34 + "guides/integrate-checkout",
35 + "guides/field-evaluation-payments",
36 + "guides/webhooks",
37 + "guides/escrow-flows"
38 + ]
39 + },
40 + {
41 + "group": "Configuration",
42 + "pages": [
43 + "configuration/environment",
44 + "configuration/vector-store",
45 + "configuration/ai-agents"
46 + ]
47 + }
48 + ]
49 + },
50 + {
51 + "tab": "API Reference",
52 + "groups": [
53 + {
54 + "group": "Orchestration",
55 + "pages": [
56 + "api/orchestrate",
57 + "api/sessions-prefill",
58 + "api/sessions-transition",
59 + "api/sessions-escrow-accept",
60 + "api/sessions-funding-method"
61 + ]
62 + },
63 + {
64 + "group": "Payments",
65 + "pages": [
66 + "api/usdc-request",
67 + "api/usdc-watch",
68 + "api/usdc-manual-confirm"
69 + ]
70 + },
71 + {
72 + "group": "Webhooks",
73 + "pages": [
74 + "api/webhook-procurement"
75 + ]
76 + }
77 + ]
78 + }
79 + ]
80 + },
81 + "keyFeatures": [
82 + "Wallet Confidence Score (WCS) engine that classifies buyer sessions and routes them to resolved, partial, or anonymous checkout flows",
83 + "Stateful session orchestration API (v7) with SSE and WebSocket transport based on session mode",
84 + "VCI field evaluation to USDC stablecoin payment bridge with GPS-tagged offline sync",
85 + "Escrow acceptance flow for high-value transactions with legal compliance checkpoints",
86 + "OpenClaw AI agent swarm (10+ worker classes) for intelligent procurement automation",
87 + "Local-first vector store for WCS profiles, contract rules, translations, and entitlements",
88 + "Procurement Express webhook integration with HMAC signature verification",
89 + "Multi-chain USDC settlement on Base, Arbitrum, Polygon, and Ethereum"
90 + ],
91 + "publicApiSurface": [
92 + "POST /api/v7/orchestrate",
93 + "GET /api/v7/sessions/{id}/prefill",
94 + "POST /api/v7/sessions/{id}/escrow-accept",
95 + "POST /api/v7/sessions/{id}/transition",
96 + "POST /api/v7/sessions/{id}/funding-method",
97 + "POST /webhooks/procurement",
98 + "POST /mods/procurement_wallet/usdc/request",
99 + "GET /mods/procurement_wallet/usdc/watch/{paymentId}",
100 + "POST /mods/procurement_wallet/usdc/manual-confirm",
101 + "WCSEngine.score(signals) → WCSResult",
102 + "VCIProcureNetBridge.handleSyncEvent(event) → PaymentRequest"
103 + ]
104 +}
api/orchestrate.mdx new
+127
@@ -0,0 +1,127 @@
1 +---
2 +title: "POST /api/v7/orchestrate — Start Procurement Session"
3 +sidebarTitle: "POST /orchestrate"
4 +description: "Start a procurement session. ProcureNet scores buyer identity hints and returns a session ID, WCS score, routing mode, and transport channel."
5 +---
6 +
7 +The `/api/v7/orchestrate` endpoint is the entry point for every procurement session. You submit a transaction amount, currency, and optional buyer identity hints; ProcureNet's Wallet Confidence Score (WCS) engine evaluates those hints, assigns a score from 0 to 200, and returns a session ID along with the resolved routing mode and the transport channel your client should open. No authentication is required on this call — the WCS engine derives trust from the hints you supply, not from a credential.
8 +
9 +## Request Body
10 +
11 +<ParamField body="amount" type="number" required>
12 + The transaction amount in the specified currency. For example, `1500.00`.
13 +</ParamField>
14 +
15 +<ParamField body="currency" type="string" required>
16 + ISO 4217 currency code for the transaction. For example, `"USD"` or `"EUR"`.
17 +</ParamField>
18 +
19 +<ParamField body="hints" type="object">
20 + Optional buyer identity signals used to calculate the WCS. The more signals you provide, the higher the score and the more prefill and SSE transport features become available.
21 +
22 + <Expandable title="hints fields">
23 + <ParamField body="hints.customerId" type="string">
24 + A known, persistent customer ID from your system. Contributes **100 points** to the WCS — the single highest-weight signal. Providing this alone is sufficient to reach the `resolved` threshold.
25 + </ParamField>
26 +
27 + <ParamField body="hints.email" type="string">
28 + The buyer's email address. Contributes **40 points** to the WCS.
29 + </ParamField>
30 +
31 + <ParamField body="hints.phone" type="string">
32 + The buyer's phone number in E.164 format (e.g., `"+15551234567"`). Contributes **40 points** to the WCS.
33 + </ParamField>
34 +
35 + <ParamField body="hints.deviceId" type="string">
36 + A device fingerprint or identifier for the buyer's current device. Contributes **20 points** to the WCS.
37 + </ParamField>
38 + </Expandable>
39 +</ParamField>
40 +
41 +<Note>
42 + The maximum possible WCS is **200** (all four hints provided). A score of **≥ 100** resolves the session to `resolved` mode with SSE transport. Scores of **40–99** produce `partial` mode, and scores **below 40** produce `anonymous` mode — both use WebSocket transport.
43 +</Note>
44 +
45 +## Request Example
46 +
47 +```typescript
48 +const res = await fetch('https://api.procurenet.io/api/v7/orchestrate', {
49 + method: 'POST',
50 + headers: { 'Content-Type': 'application/json' },
51 + body: JSON.stringify({
52 + amount: 1500.00,
53 + currency: 'USD',
54 + hints: {
55 + customerId: 'cust_8f2a1b',
56 + email: 'buyer@example.com',
57 + phone: '+15551234567',
58 + deviceId: 'dev_9c3d2e'
59 + }
60 + })
61 +});
62 +
63 +const session = await res.json();
64 +// {
65 +// session_id: 'sess_abc123',
66 +// wcs_score: 200,
67 +// mode: 'resolved',
68 +// transport: 'sse'
69 +// }
70 +```
71 +
72 +## Response Fields
73 +
74 +<ResponseField name="session_id" type="string" required>
75 + The unique session identifier. Pass this as the `{id}` path parameter in all subsequent session calls: prefill, transition, escrow-accept, and funding-method.
76 +</ResponseField>
77 +
78 +<ResponseField name="wcs_score" type="integer" required>
79 + The calculated Wallet Confidence Score, ranging from `0` to `200`. Reflects the sum of the hint weights provided.
80 +</ResponseField>
81 +
82 +<ResponseField name="mode" type="string" required>
83 + The resolved session classification. One of:
84 +
85 + | Value | WCS Range | Meaning |
86 + |---|---|---|
87 + | `resolved` | ≥ 100 | Full buyer identity confirmed; prefill available |
88 + | `partial` | 40–99 | Partial identity; limited prefill |
89 + | `anonymous` | < 40 | No reliable identity signals |
90 +</ResponseField>
91 +
92 +<ResponseField name="transport" type="string" required>
93 + The recommended transport channel for real-time session events. `sse` for `resolved` sessions; `websocket` for `partial` and `anonymous`.
94 +</ResponseField>
95 +
96 +## Response Example
97 +
98 +```json
99 +{
100 + "session_id": "sess_abc123",
101 + "wcs_score": 200,
102 + "mode": "resolved",
103 + "transport": "sse"
104 +}
105 +```
106 +
107 +## WCS Score Reference
108 +
109 +<CardGroup cols={3}>
110 + <Card title="resolved" icon="circle-check">
111 + Score **≥ 100** — Full prefill access, SSE transport, all session features unlocked.
112 + </Card>
113 + <Card title="partial" icon="circle-half-stroke">
114 + Score **40–99** — Reduced prefill, WebSocket transport required.
115 + </Card>
116 + <Card title="anonymous" icon="circle-xmark">
117 + Score **< 40** — No prefill available, WebSocket transport required.
118 + </Card>
119 +</CardGroup>
120 +
121 +## Error Codes
122 +
123 +| HTTP Status | Description |
124 +|---|---|
125 +| `400 Bad Request` | Missing required fields (`amount` or `currency`), or malformed request body. |
126 +| `422 Unprocessable Entity` | Field validation failed — for example, an unrecognized `currency` code. |
127 +| `500 Internal Server Error` | WCS engine or orchestration pipeline failure. Retry with exponential backoff. |
api/sessions-escrow-accept.mdx new
+113
@@ -0,0 +1,113 @@
1 +---
2 +title: "POST /api/v7/sessions/{id}/escrow-accept"
3 +sidebarTitle: "POST /escrow-accept"
4 +description: "Accept escrow for a high-value procurement session. Writes an immutable audit trail entry before confirmation. This action cannot be undone."
5 +---
6 +
7 +When a procurement session involves a transaction above the high-value threshold, ProcureNet moves the session into `escrow_pending` state and requires explicit escrow acceptance before payment can proceed. This endpoint records your acceptance, writes an immutable audit trail entry, and advances the session so the payment pipeline can continue. Because this action has legal and financial consequences, the endpoint requires a valid Bearer JWT and performs strict session-scope verification before committing anything.
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`. A valid token that does not own the session receives `403 Forbidden`.
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 currently be in `escrow_pending` state.
23 +</ParamField>
24 +
25 +## Request Body
26 +
27 +No request body is required. Send the request with no body, or an empty JSON object.
28 +
29 +## Request Example
30 +
31 +```typescript
32 +const sessionId = 'sess_abc123';
33 +
34 +const res = await fetch(
35 + `https://api.procurenet.io/api/v7/sessions/${sessionId}/escrow-accept`,
36 + {
37 + method: 'POST',
38 + headers: {
39 + 'Authorization': 'Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...',
40 + 'Content-Type': 'application/json'
41 + }
42 + }
43 +);
44 +
45 +const result = await res.json();
46 +// {
47 +// "session_id": "sess_abc123",
48 +// "status": "escrow_accepted",
49 +// "audit_entry_id": "audit_7x9k2m",
50 +// "accepted_at": "2026-04-01T15:04:22Z"
51 +// }
52 +```
53 +
54 +## Response Fields
55 +
56 +<ResponseField name="session_id" type="string" required>
57 + Echoes back the session ID for correlation.
58 +</ResponseField>
59 +
60 +<ResponseField name="status" type="string" required>
61 + The new session status after acceptance. Will be `"escrow_accepted"` on success.
62 +</ResponseField>
63 +
64 +<ResponseField name="audit_entry_id" type="string" required>
65 + The unique identifier for the immutable audit trail record written at the moment of acceptance. Retain this value for compliance and dispute resolution.
66 +</ResponseField>
67 +
68 +<ResponseField name="accepted_at" type="string" required>
69 + ISO 8601 timestamp of when the escrow acceptance was recorded. This timestamp is co-written to the audit trail and cannot be amended.
70 +</ResponseField>
71 +
72 +## Response Example
73 +
74 +```json
75 +{
76 + "session_id": "sess_abc123",
77 + "status": "escrow_accepted",
78 + "audit_entry_id": "audit_7x9k2m",
79 + "accepted_at": "2026-04-01T15:04:22Z"
80 +}
81 +```
82 +
83 +<Warning>
84 + **Escrow acceptance is irreversible.** Once this endpoint returns `200`, the audit trail entry is sealed and cannot be modified or deleted. Ensure the buyer has explicitly confirmed the transaction before calling this endpoint. If you need to cancel after acceptance, contact ProcureNet support — a manual reversal process exists but is subject to review.
85 +</Warning>
86 +
87 +## Typical Flow
88 +
89 +<Steps>
90 + <Step title="Detect escrow_pending state">
91 + After calling `POST /api/v7/sessions/{id}/transition`, check whether the response `current_state` is `escrow_pending`. This indicates the transaction exceeded the high-value threshold.
92 + </Step>
93 + <Step title="Present escrow disclosure to the buyer">
94 + Display the transaction amount, escrow terms, and an explicit confirmation prompt to the buyer. Do not call this endpoint until the buyer actively confirms.
95 + </Step>
96 + <Step title="Call escrow-accept">
97 + Send the `POST` request with the session ID and your Bearer JWT. Store the `audit_entry_id` from the response in your own records.
98 + </Step>
99 + <Step title="Proceed to funding">
100 + After a successful `200` response, call `POST /api/v7/sessions/{id}/funding-method` to complete the payment setup.
101 + </Step>
102 +</Steps>
103 +
104 +## Error Codes
105 +
106 +| HTTP Status | Description |
107 +|---|---|
108 +| `401 Unauthorized` | Missing, expired, or invalid Bearer JWT. |
109 +| `403 Forbidden` | The authenticated identity does not match the session owner, or the session is not in `escrow_pending` state. |
110 +| `404 Not Found` | No session exists for the provided `id`. |
111 +| `409 Conflict` | Escrow has already been accepted for this session. Check your `audit_entry_id` from the original call. |
112 +| `410 Gone` | The session has expired. Start a new session with `POST /api/v7/orchestrate`. |
113 +| `500 Internal Server Error` | Audit trail write failure. The acceptance was **not** recorded. Safe to retry. |
api/sessions-funding-method.mdx new
+208
@@ -0,0 +1,208 @@
1 +---
2 +title: "POST /api/v7/sessions/{id}/funding-method"
3 +sidebarTitle: "POST /funding-method"
4 +description: "Bind a payment method to an active procurement session. Accepts USDC on-chain, card, or bank transfer. 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, or bank transfer — and for USDC payments, the target blockchain network. ProcureNet validates the combination against the session's state and the buyer's entitlements stored in the local vector store, 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 field is ignored. |
34 + | `bank_transfer` | ACH or wire transfer. Network field is ignored. |
35 +</ParamField>
36 +
37 +<ParamField body="network" type="string">
38 + The blockchain network for USDC transfers. Required when `method` is `"usdc"`. Ignored for all other methods.
39 +
40 + Supported values: `base`, `arbitrum`, `polygon`, `ethereum`.
41 +
42 + <Tip>
43 + `base` offers the lowest gas fees for most USDC transfers and is the recommended network unless your buyer or contract rules require otherwise.
44 + </Tip>
45 +</ParamField>
46 +
47 +## Request Examples
48 +
49 +<CodeGroup>
50 +
51 +```typescript USDC on Base
52 +const sessionId = 'sess_abc123';
53 +
54 +const res = await fetch(
55 + `https://api.procurenet.io/api/v7/sessions/${sessionId}/funding-method`,
56 + {
57 + method: 'POST',
58 + headers: {
59 + 'Authorization': 'Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...',
60 + 'Content-Type': 'application/json'
61 + },
62 + body: JSON.stringify({
63 + method: 'usdc',
64 + network: 'base'
65 + })
66 + }
67 +);
68 +
69 +const result = await res.json();
70 +```
71 +
72 +```typescript Card Payment
73 +const sessionId = 'sess_abc123';
74 +
75 +const res = await fetch(
76 + `https://api.procurenet.io/api/v7/sessions/${sessionId}/funding-method`,
77 + {
78 + method: 'POST',
79 + headers: {
80 + 'Authorization': 'Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...',
81 + 'Content-Type': 'application/json'
82 + },
83 + body: JSON.stringify({
84 + method: 'card'
85 + })
86 + }
87 +);
88 +
89 +const result = await res.json();
90 +```
91 +
92 +```typescript Bank Transfer
93 +const sessionId = 'sess_abc123';
94 +
95 +const res = await fetch(
96 + `https://api.procurenet.io/api/v7/sessions/${sessionId}/funding-method`,
97 + {
98 + method: 'POST',
99 + headers: {
100 + 'Authorization': 'Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...',
101 + 'Content-Type': 'application/json'
102 + },
103 + body: JSON.stringify({
104 + method: 'bank_transfer'
105 + })
106 + }
107 +);
108 +
109 +const result = await res.json();
110 +```
111 +
112 +</CodeGroup>
113 +
114 +## Response Fields
115 +
116 +<ResponseField name="session_id" type="string" required>
117 + Echoes back the session ID.
118 +</ResponseField>
119 +
120 +<ResponseField name="method" type="string" required>
121 + Confirms the payment method that was bound to the session.
122 +</ResponseField>
123 +
124 +<ResponseField name="network" type="string">
125 + The blockchain network confirmed for USDC transfers. Present only when `method` is `"usdc"`.
126 +</ResponseField>
127 +
128 +<ResponseField name="status" type="string" required>
129 + The session status after the funding method was set. Typically `"payment_processing"` once the session advances.
130 +</ResponseField>
131 +
132 +## Response Example
133 +
134 +```json
135 +{
136 + "session_id": "sess_abc123",
137 + "method": "usdc",
138 + "network": "base",
139 + "status": "payment_processing"
140 +}
141 +```
142 +
143 +## Supported Networks for USDC
144 +
145 +<CardGroup cols={2}>
146 + <Card title="Base" icon="circle-check">
147 + Lowest fees. Recommended for most USDC transactions.
148 + </Card>
149 + <Card title="Arbitrum" icon="circle-check">
150 + Low fees, high throughput. Good alternative to Base.
151 + </Card>
152 + <Card title="Polygon" icon="circle-check">
153 + Widely supported. Use when buyer wallets are Polygon-native.
154 + </Card>
155 + <Card title="Ethereum" icon="circle-check">
156 + Highest security and liquidity. Higher gas fees apply.
157 + </Card>
158 +</CardGroup>
159 +
160 +## Migration from POST /api/payments/route
161 +
162 +<Note>
163 + `POST /api/payments/route` is **deprecated** and will be removed in a future release. Migrate all integrations to the v7 session flow.
164 +</Note>
165 +
166 +Replace your existing single-call payment routing with the two-step v7 session pattern:
167 +
168 +<Steps>
169 + <Step title="Start an orchestration session">
170 + 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.
171 +
172 + ```typescript
173 + // Before (deprecated)
174 + await fetch('/api/payments/route', {
175 + method: 'POST',
176 + body: JSON.stringify({ amount: 500, currency: 'USD', paymentMethod: 'usdc' })
177 + });
178 +
179 + // After
180 + const session = await fetch('/api/v7/orchestrate', {
181 + method: 'POST',
182 + body: JSON.stringify({ amount: 500, currency: 'USD', hints: { email: 'buyer@example.com' } })
183 + }).then(r => r.json());
184 + ```
185 + </Step>
186 + <Step title="Set the funding method on the session">
187 + Take the `session_id` from the orchestrate response and call this endpoint to bind your payment method.
188 +
189 + ```typescript
190 + await fetch(`/api/v7/sessions/${session.session_id}/funding-method`, {
191 + method: 'POST',
192 + headers: { 'Authorization': `Bearer ${jwt}` },
193 + body: JSON.stringify({ method: 'usdc', network: 'base' })
194 + });
195 + ```
196 + </Step>
197 +</Steps>
198 +
199 +## Error Codes
200 +
201 +| HTTP Status | Description |
202 +|---|---|
203 +| `400 Bad Request` | Missing required fields, unrecognized `method` value, or `method` is `"usdc"` but `network` is absent or invalid. |
204 +| `401 Unauthorized` | Missing, expired, or invalid Bearer JWT. |
205 +| `403 Forbidden` | The session state does not permit setting a funding method at this point (for example, escrow acceptance is still required). |
206 +| `404 Not Found` | No session exists for the provided `id`. |
207 +| `409 Conflict` | A funding method is already set for this session. Transition to a new session if you need to change it. |
208 +| `410 Gone` | The session has expired. Start a new session with `POST /api/v7/orchestrate`. |
api/sessions-prefill.mdx new
+135
@@ -0,0 +1,135 @@
1 +---
2 +title: "GET /api/v7/sessions/{id}/prefill — Buyer Prefill Data"
3 +sidebarTitle: "GET /prefill"
4 +description: "Retrieve cached buyer profile and payment preferences for a resolved session. Only available when the session's Wallet Confidence Score is 100 or above."
5 +---
6 +
7 +When ProcureNet resolves a session with a Wallet Confidence Score of 100 or higher, it caches the buyer's known profile data in the local-first vector store and makes it available through the prefill endpoint. Fetching this data lets your checkout UI pre-populate name, address, and payment preference fields, reducing friction for returning buyers. If the session was classified as `partial` or `anonymous`, this endpoint returns `403` — you must present the buyer with a manual entry form instead.
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`. This scopes the prefill lookup to the correct buyer session.
23 +</ParamField>
24 +
25 +## Request Example
26 +
27 +```typescript
28 +const sessionId = 'sess_abc123';
29 +
30 +const res = await fetch(
31 + `https://api.procurenet.io/api/v7/sessions/${sessionId}/prefill`,
32 + {
33 + method: 'GET',
34 + headers: {
35 + 'Authorization': 'Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...',
36 + 'Content-Type': 'application/json'
37 + }
38 + }
39 +);
40 +
41 +const prefill = await res.json();
42 +// {
43 +// "customer": {
44 +// "name": "Jordan Reeves",
45 +// "email": "buyer@example.com",
46 +// "address": {
47 +// "line1": "123 Main St",
48 +// "city": "Austin",
49 +// "state": "TX",
50 +// "zip": "78701",
51 +// "country": "US"
52 +// }
53 +// },
54 +// "payment_preferences": ["usdc", "card"]
55 +// }
56 +```
57 +
58 +## Response Fields
59 +
60 +<ResponseField name="customer" type="object" required>
61 + A profile object containing the buyer's known identity fields. The exact shape depends on what was available when ProcureNet built the WCS profile.
62 +
63 + <Expandable title="customer fields">
64 + <ResponseField name="customer.name" type="string">
65 + The buyer's full name as stored in the resolved profile.
66 + </ResponseField>
67 +
68 + <ResponseField name="customer.email" type="string">
69 + The buyer's email address.
70 + </ResponseField>
71 +
72 + <ResponseField name="customer.address" type="object">
73 + Structured shipping or billing address, when available.
74 + </ResponseField>
75 + </Expandable>
76 +</ResponseField>
77 +
78 +<ResponseField name="payment_preferences" type="string[]" required>
79 + An ordered list of the buyer's preferred payment methods, from most to least preferred. Possible values include `"usdc"`, `"card"`, and `"bank_transfer"`. Use this list to rank the options you present in your funding-method UI.
80 +</ResponseField>
81 +
82 +## Response Example
83 +
84 +```json
85 +{
86 + "customer": {
87 + "name": "Jordan Reeves",
88 + "email": "buyer@example.com",
89 + "address": {
90 + "line1": "123 Main St",
91 + "city": "Austin",
92 + "state": "TX",
93 + "zip": "78701",
94 + "country": "US"
95 + }
96 + },
97 + "payment_preferences": ["usdc", "card"]
98 +}
99 +```
100 +
101 +<Tip>
102 + Use `payment_preferences[0]` as the default selection in your funding-method UI, then pass it to `POST /api/v7/sessions/{id}/funding-method` when the buyer confirms.
103 +</Tip>
104 +
105 +## Eligibility Check
106 +
107 +Before calling this endpoint, inspect the `mode` field from your `POST /api/v7/orchestrate` response:
108 +
109 +<Tabs>
110 + <Tab title="Eligible — resolved">
111 + ```typescript
112 + if (session.mode === 'resolved') {
113 + const prefill = await fetchPrefill(session.session_id, jwt);
114 + populateCheckoutForm(prefill);
115 + }
116 + ```
117 + </Tab>
118 + <Tab title="Not eligible — partial / anonymous">
119 + ```typescript
120 + if (session.mode !== 'resolved') {
121 + // Skip prefill — render manual entry form
122 + renderManualEntryForm();
123 + }
124 + ```
125 + </Tab>
126 +</Tabs>
127 +
128 +## Error Codes
129 +
130 +| HTTP Status | Description |
131 +|---|---|
132 +| `401 Unauthorized` | Missing, expired, or invalid Bearer JWT. |
133 +| `403 Forbidden` | The session's WCS is below 100 (`partial` or `anonymous` mode). Prefill is not available for this session. |
134 +| `404 Not Found` | No session exists for the provided `id`. |
135 +| `500 Internal Server Error` | Vector store lookup failure. Retry the request. |
api/sessions-transition.mdx new
+131
@@ -0,0 +1,131 @@
1 +---
2 +title: "POST /api/v7/sessions/{id}/transition — Advance State"
3 +sidebarTitle: "POST /transition"
4 +description: "Advance a session through the procurement state machine. Illegal moves return deterministic error codes. Every call emits an observability pipeline event."
5 +---
6 +
7 +ProcureNet manages each procurement session as a strict state machine. Calling this endpoint moves the session forward to a target state you specify. The engine validates that the transition is permitted from the session's current state — if it isn't, you receive a deterministic `400` error with a machine-readable rejection code so your integration can handle it without guesswork. Every successful transition also emits an event to the observability pipeline, giving you a complete, timestamped audit trail of how a session progressed.
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`. Identifies the session whose state machine you are advancing.
23 +</ParamField>
24 +
25 +## Request Body
26 +
27 +<ParamField body="to" type="string" required>
28 + The target state to transition the session into. The engine enforces which transitions are valid from the session's current state and rejects any that are out of sequence.
29 +
30 + Common target states include:
31 +
32 + | State | Meaning |
33 + |---|---|
34 + | `pending_payment` | Buyer has confirmed their cart; awaiting funding method |
35 + | `escrow_pending` | High-value transaction detected; escrow acceptance required |
36 + | `payment_processing` | Funding method submitted; payment is in flight |
37 + | `completed` | Transaction finalized |
38 + | `cancelled` | Session terminated by buyer or system |
39 +</ParamField>
40 +
41 +## Request Example
42 +
43 +```typescript
44 +const sessionId = 'sess_abc123';
45 +
46 +const res = await fetch(
47 + `https://api.procurenet.io/api/v7/sessions/${sessionId}/transition`,
48 + {
49 + method: 'POST',
50 + headers: {
51 + 'Authorization': 'Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...',
52 + 'Content-Type': 'application/json'
53 + },
54 + body: JSON.stringify({ to: 'pending_payment' })
55 + }
56 +);
57 +
58 +const result = await res.json();
59 +// {
60 +// "session_id": "sess_abc123",
61 +// "previous_state": "orchestrated",
62 +// "current_state": "pending_payment",
63 +// "transitioned_at": "2026-04-01T14:23:11Z"
64 +// }
65 +```
66 +
67 +## Response Fields
68 +
69 +<ResponseField name="session_id" type="string" required>
70 + Echoes back the session ID for correlation in your logs.
71 +</ResponseField>
72 +
73 +<ResponseField name="previous_state" type="string" required>
74 + The state the session was in immediately before this transition.
75 +</ResponseField>
76 +
77 +<ResponseField name="current_state" type="string" required>
78 + The state the session has moved into as a result of this call. This will match the `to` value you submitted.
79 +</ResponseField>
80 +
81 +<ResponseField name="transitioned_at" type="string" required>
82 + ISO 8601 timestamp of when the transition was recorded. This is the same timestamp written to the observability pipeline event.
83 +</ResponseField>
84 +
85 +## Response Example
86 +
87 +```json
88 +{
89 + "session_id": "sess_abc123",
90 + "previous_state": "orchestrated",
91 + "current_state": "pending_payment",
92 + "transitioned_at": "2026-04-01T14:23:11Z"
93 +}
94 +```
95 +
96 +## Handling Illegal Transitions
97 +
98 +If you attempt a transition that is not valid from the session's current state, the engine returns `400` with a structured error body. Parse the `code` field to drive retry or fallback logic in your integration.
99 +
100 +```typescript
101 +if (!res.ok) {
102 + const err = await res.json();
103 + // err.code === 'ILLEGAL_TRANSITION'
104 + // err.current_state === 'payment_processing'
105 + // err.attempted === 'pending_payment'
106 + console.error(`Cannot transition: ${err.message}`);
107 +}
108 +```
109 +
110 +```json
111 +{
112 + "code": "ILLEGAL_TRANSITION",
113 + "message": "Cannot move to 'pending_payment' from 'payment_processing'.",
114 + "current_state": "payment_processing",
115 + "attempted": "pending_payment"
116 +}
117 +```
118 +
119 +<Info>
120 + Every successful transition — and every rejected attempt — is emitted as a structured event to the ProcureNet observability pipeline. You can use these events to reconstruct the full lifecycle of any session for debugging or compliance purposes.
121 +</Info>
122 +
123 +## Error Codes
124 +
125 +| HTTP Status | Code | Description |
126 +|---|---|---|
127 +| `400 Bad Request` | `ILLEGAL_TRANSITION` | The `to` state is not reachable from the session's current state. |
128 +| `400 Bad Request` | `UNKNOWN_STATE` | The `to` value is not a recognized session state. |
129 +| `401 Unauthorized` | — | Missing, expired, or invalid Bearer JWT. |
130 +| `404 Not Found` | — | No session exists for the provided `id`. |
131 +| `410 Gone` | `SESSION_EXPIRED` | The session has passed its TTL and can no longer be transitioned. Start a new session with `POST /api/v7/orchestrate`. |
api/usdc-manual-confirm.mdx new
+138
@@ -0,0 +1,138 @@
1 +---
2 +title: "Manually Confirm a USDC Payment — Admin Override"
3 +sidebarTitle: "POST /manual-confirm"
4 +description: "Force-confirm a pending USDC payment request using elevated admin credentials. Use when autoWatch is disabled or automated confirmation has stalled."
5 +---
6 +
7 +The manual confirmation endpoint lets an administrator force a USDC payment into confirmed status without waiting for the automated on-chain watch cycle. This is an elevated operation intended for operational recovery — use it when `autoWatch` is disabled on your `ProcureNetWalletClient`, when a payment has stalled due to network delays, or when you need to confirm a payment outside the normal polling window. The `VCIProcureNetBridge` exposes this via the `manualConfirmPayment()` method, which accepts a local queue record ID and resolves the associated `payment_id` automatically.
8 +
9 +## Endpoint
10 +
11 +```http
12 +POST /mods/procurement_wallet/usdc/manual-confirm
13 +```
14 +
15 +## Authentication
16 +
17 +This endpoint requires **both** your mod API key and an admin key. Both headers must be present and valid; a missing or invalid header on either returns `401`.
18 +
19 +```text
20 +x-perplexity-mod-key: <your-api-key>
21 +x-admin-key: <your-admin-key>
22 +```
23 +
24 +<Warning>
25 + Your admin key is an elevated credential that bypasses normal on-chain confirmation requirements. Never expose `x-admin-key` in client-side code, browser environments, or mobile apps. Restrict all calls to this endpoint to server-side admin workflows with access controls and audit logging in place.
26 +</Warning>
27 +
28 +## Request Body
29 +
30 +<ParamField body="payment_id" type="string" required>
31 + The `payment_id` of the payment you want to manually confirm. You can retrieve this from the original create-request response, or from the queue record's metadata under the key `procurenet_payment_id` when using `VCIProcureNetBridge`.
32 +</ParamField>
33 +
34 +## Code Example
35 +
36 +<CodeGroup>
37 +```typescript TypeScript
38 +import { VCIProcureNetBridge, ProcureNetWalletClient } from './integrations/VCIProcureNetBridge';
39 +
40 +// Using VCIProcureNetBridge (resolves payment_id from queue record automatically)
41 +const result = await bridge.manualConfirmPayment(
42 + localId, // local queue record ID (number)
43 + process.env.ADMIN_KEY!
44 +);
45 +
46 +if (result.confirmed) {
47 + console.log('Payment manually confirmed. TX:', result.transaction_hash);
48 +} else {
49 + console.warn('Manual confirmation did not result in a confirmed status.');
50 +}
51 +```
52 +
53 +```typescript Direct Client Call
54 +import { ProcureNetWalletClient } from './integrations/VCIProcureNetBridge';
55 +
56 +const wallet = new ProcureNetWalletClient(
57 + 'https://api.procurenet.io',
58 + process.env.PROCURENET_MOD_KEY!
59 +);
60 +
61 +const result = await wallet.manualConfirm(
62 + 'pay_xyz789',
63 + process.env.ADMIN_KEY!
64 +);
65 +
66 +if (result.confirmed) {
67 + console.log('Transaction hash:', result.transaction_hash);
68 +}
69 +```
70 +
71 +```bash cURL
72 +curl -X POST https://api.procurenet.io/mods/procurement_wallet/usdc/manual-confirm \
73 + -H "Content-Type: application/json" \
74 + -H "x-perplexity-mod-key: $PROCURENET_MOD_KEY" \
75 + -H "x-admin-key: $ADMIN_KEY" \
76 + -d '{ "payment_id": "pay_xyz789" }'
77 +```
78 +</CodeGroup>
79 +
80 +## When to Use Manual Confirmation
81 +
82 +<CardGroup cols={2}>
83 + <Card title="autoWatch Disabled" icon="eye-slash">
84 + If you initialized `ProcureNetWalletClient` with `autoWatch: false`, the bridge will not poll for on-chain confirmations. Use this endpoint to confirm payments after you have verified the transfer through an external source.
85 + </Card>
86 + <Card title="Stalled Confirmation" icon="clock">
87 + If a payment remains unconfirmed longer than expected — for example, due to network congestion on Ethereum mainnet — you can use this endpoint to unblock the settlement queue.
88 + </Card>
89 + <Card title="Operational Recovery" icon="wrench">
90 + During incidents where the watch service is temporarily unavailable, you can replay confirmations for all affected payments using this endpoint from a secure admin context.
91 + </Card>
92 + <Card title="Testing & Staging" icon="flask">
93 + In non-production environments where you are not routing real on-chain transfers, use manual confirmation to exercise the rest of your payment settlement workflow without waiting for blockchain activity.
94 + </Card>
95 +</CardGroup>
96 +
97 +## Response
98 +
99 +<ResponseField name="confirmed" type="boolean" required>
100 + `true` when the payment has been successfully force-confirmed. In most cases this will be `true` on a valid request, but may return `false` if the payment is already in a terminal failure state.
101 +</ResponseField>
102 +
103 +<ResponseField name="transaction_hash" type="string">
104 + The blockchain transaction hash if one is available. For manually confirmed payments, this may be absent if the payment was confirmed without a corresponding on-chain transfer.
105 +</ResponseField>
106 +
107 +### Example Response
108 +
109 +```json
110 +{
111 + "confirmed": true,
112 + "transaction_hash": "0x4f3c8b2a1e9d7f6c0b5a4e3d2c1b0a9f8e7d6c5b4a3f2e1d0c9b8a7f6e5d4c3b"
113 +}
114 +```
115 +
116 +## Bridge Behavior After Confirmation
117 +
118 +When you call `bridge.manualConfirmPayment()`, the bridge automatically writes back to the queue record on success:
119 +
120 +```typescript
121 +await this.queue.updateRecordMetadata(localId, {
122 + status: 'payment_confirmed',
123 + tx_hash: result.transaction_hash,
124 +});
125 +```
126 +
127 +This keeps your offline queue in sync with the confirmed payment state so downstream processes see the record as fully settled.
128 +
129 +## Error Codes
130 +
131 +| Status | Meaning |
132 +|---|---|
133 +| `401` | Missing or invalid `x-perplexity-mod-key` or `x-admin-key` header |
134 +| `404` | No payment found for the given `payment_id` |
135 +
136 +<Info>
137 + If you need to confirm payments in bulk — for example, to recover a batch of stalled evaluations — iterate over affected local queue records and call `bridge.manualConfirmPayment()` for each one. The bridge resolves `payment_id` for you from the queue metadata, so you only need the local record ID.
138 +</Info>
api/usdc-request.mdx new
+152
@@ -0,0 +1,152 @@
1 +---
2 +title: "Create a USDC Payment Request — ProcureNet Wallet"
3 +sidebarTitle: "POST /usdc/request"
4 +description: "Initiate an on-chain USDC payment request for a tenant. Returns a deposit address, optional QR code, and a payment_id to track confirmation."
5 +---
6 +
7 +The USDC payment request endpoint creates an on-chain payment instruction for a specific tenant and amount. When a field evaluator's offline evaluation syncs successfully, `VCIProcureNetBridge` calls this endpoint automatically to initiate settlement. You can also call it directly to request payment outside of the automated sync flow. Each response includes a `payment_id` you can pass to the watch or manual-confirm endpoints to track the transaction's on-chain status.
8 +
9 +## Endpoint
10 +
11 +```http
12 +POST /mods/procurement_wallet/usdc/request
13 +```
14 +
15 +## Authentication
16 +
17 +All requests to the wallet mod endpoints require your mod API key in the `x-perplexity-mod-key` header.
18 +
19 +```text
20 +x-perplexity-mod-key: <your-api-key>
21 +```
22 +
23 +## Request Body
24 +
25 +<ParamField body="tenant_id" type="string" required>
26 + Your tenant identifier. This must match a tenant registered in ProcureNet. Requests for unregistered tenants return `422`.
27 +</ParamField>
28 +
29 +<ParamField body="amount_usdc" type="number" required>
30 + Payment amount in USDC. Must be a positive number. The `VCIProcureNetBridge` derives this automatically from the evaluator's average score using the following tiers:
31 +
32 + | Average Score | Payment |
33 + |---|---|
34 + | ≥ 9.0 | 500 USDC |
35 + | ≥ 7.0 | 250 USDC |
36 + | ≥ 5.0 | 100 USDC |
37 + | < 5.0 | 0 USDC (no payment created) |
38 +</ParamField>
39 +
40 +<ParamField body="network" type="string" required>
41 + The blockchain network on which to route the payment. Accepted values: `base`, `arbitrum`, `polygon`, `ethereum`.
42 +</ParamField>
43 +
44 +<ParamField body="token" type="string" required>
45 + Token type. Always pass `"USDC"`.
46 +</ParamField>
47 +
48 +<ParamField body="memo" type="string" required>
49 + A human-readable description attached to the payment. For VCI evaluations, the bridge generates this automatically in the format `VCI Eval: <assignmentId> | Score: <avg>`.
50 +</ParamField>
51 +
52 +<ParamField body="metadata" type="object">
53 + Arbitrary key-value pairs attached to the payment record. Use this field to link the payment back to your internal records — for example, an evaluator ID, assignment ID, or GPS snapshot. Keys and values must be JSON-serializable.
54 +
55 + <Expandable title="Common metadata keys">
56 + | Key | Type | Description |
57 + |---|---|---|
58 + | `evaluator_id` | string | Your internal evaluator identifier |
59 + | `assignment_id` | string | The assignment this payment covers |
60 + | `vci_local_id` | number | Local offline queue record ID |
61 + | `gps` | object | GPS snapshot at time of evaluation |
62 + | `submitted_at` | string | ISO 8601 timestamp of offline submission |
63 + </Expandable>
64 +</ParamField>
65 +
66 +## Code Example
67 +
68 +<CodeGroup>
69 +```typescript TypeScript
70 +import { ProcureNetWalletClient } from './integrations/VCIProcureNetBridge';
71 +
72 +const wallet = new ProcureNetWalletClient(
73 + 'https://api.procurenet.io',
74 + process.env.PROCURENET_MOD_KEY!,
75 + { autoWatch: true }
76 +);
77 +
78 +const payment = await wallet.createUSDCPayment({
79 + tenant_id: 'tenant_abc',
80 + amount_usdc: 250,
81 + network: 'base',
82 + token: 'USDC',
83 + memo: 'VCI Eval: assign_789 | Score: 7.50',
84 + metadata: {
85 + evaluator_id: 'eval_456',
86 + assignment_id: 'assign_789'
87 + }
88 +});
89 +
90 +console.log(payment.payment_id); // 'pay_xyz789'
91 +console.log(payment.deposit_address); // '0xabc123...'
92 +console.log(payment.expires_at); // '2025-09-01T12:00:00Z'
93 +```
94 +
95 +```bash cURL
96 +curl -X POST https://api.procurenet.io/mods/procurement_wallet/usdc/request \
97 + -H "Content-Type: application/json" \
98 + -H "x-perplexity-mod-key: $PROCURENET_MOD_KEY" \
99 + -d '{
100 + "tenant_id": "tenant_abc",
101 + "amount_usdc": 250,
102 + "network": "base",
103 + "token": "USDC",
104 + "memo": "VCI Eval: assign_789 | Score: 7.50",
105 + "metadata": {
106 + "evaluator_id": "eval_456",
107 + "assignment_id": "assign_789"
108 + }
109 + }'
110 +```
111 +</CodeGroup>
112 +
113 +## Response
114 +
115 +<ResponseField name="payment_id" type="string" required>
116 + Unique identifier for this payment request. Pass this value to [`GET /usdc/watch/{paymentId}`](/api/usdc-watch) to poll confirmation, or to [`POST /usdc/manual-confirm`](/api/usdc-manual-confirm) to force-confirm.
117 +</ResponseField>
118 +
119 +<ResponseField name="deposit_address" type="string" required>
120 + The on-chain wallet address that will receive the USDC transfer.
121 +</ResponseField>
122 +
123 +<ResponseField name="qr_code" type="string">
124 + A data URI containing a QR code image for the deposit address. Render this in your UI so evaluators can scan and pay directly from a mobile wallet.
125 +</ResponseField>
126 +
127 +<ResponseField name="expires_at" type="string">
128 + ISO 8601 timestamp after which this payment request is no longer valid. If the on-chain transfer is not confirmed before this time, the request expires and you must create a new one.
129 +</ResponseField>
130 +
131 +### Example Response
132 +
133 +```json
134 +{
135 + "payment_id": "pay_xyz789",
136 + "deposit_address": "0xabc123def456abc123def456abc123def456abc1",
137 + "qr_code": "data:image/png;base64,iVBORw0KGgo...",
138 + "expires_at": "2025-09-01T12:00:00Z"
139 +}
140 +```
141 +
142 +## Error Codes
143 +
144 +| Status | Meaning |
145 +|---|---|
146 +| `400` | Invalid `network` value or `amount_usdc` is zero or negative |
147 +| `401` | Missing or invalid `x-perplexity-mod-key` header |
148 +| `422` | `tenant_id` does not match a registered ProcureNet tenant |
149 +
150 +<Tip>
151 + Store `payment_id` and `deposit_address` in your queue metadata immediately after a successful response. The `VCIProcureNetBridge` does this automatically via `queue.updateRecordMetadata()`.
152 +</Tip>
api/usdc-watch.mdx new
+121
@@ -0,0 +1,121 @@
1 +---
2 +title: "Poll USDC Payment Confirmation — Watch Endpoint"
3 +sidebarTitle: "GET /usdc/watch"
4 +description: "Poll an active USDC payment request for on-chain confirmation. Returns confirmed status and a transaction hash once the transfer is detected."
5 +---
6 +
7 +After creating a USDC payment request, use the watch endpoint to check whether the corresponding on-chain transfer has been confirmed. You call this endpoint periodically, passing the `payment_id` returned by the create endpoint, until `confirmed` is `true`. When you initialize `ProcureNetWalletClient` with `autoWatch: true`, the `VCIProcureNetBridge` handles this polling loop automatically after every successful evaluation sync — you only need to call this endpoint directly when managing the polling lifecycle yourself.
8 +
9 +## Endpoint
10 +
11 +```http
12 +GET /mods/procurement_wallet/usdc/watch/{paymentId}
13 +```
14 +
15 +## Authentication
16 +
17 +Requests require your mod API key in the `x-perplexity-mod-key` header.
18 +
19 +```text
20 +x-perplexity-mod-key: <your-api-key>
21 +```
22 +
23 +## Path Parameters
24 +
25 +<ParamField path="paymentId" type="string" required>
26 + The `payment_id` returned when you created the payment request via [`POST /usdc/request`](/api/usdc-request). This value is also stored in your queue record's metadata under the key `procurenet_payment_id` when using `VCIProcureNetBridge`.
27 +</ParamField>
28 +
29 +## Polling Behavior
30 +
31 +Call this endpoint on a fixed interval until the response includes `"confirmed": true`. A reasonable starting interval is every 10–15 seconds for `base` and `arbitrum` networks, and every 30–60 seconds for `ethereum` mainnet.
32 +
33 +<Note>
34 + If `autoWatch: true` is set on your `ProcureNetWalletClient` instance, `VCIProcureNetBridge` automatically calls `watchPayment()` for you after initiating settlement. You do not need to poll manually in that case.
35 +</Note>
36 +
37 +## Code Example
38 +
39 +<CodeGroup>
40 +```typescript TypeScript
41 +import { ProcureNetWalletClient } from './integrations/VCIProcureNetBridge';
42 +
43 +const wallet = new ProcureNetWalletClient(
44 + 'https://api.procurenet.io',
45 + process.env.PROCURENET_MOD_KEY!
46 +);
47 +
48 +// Manual polling loop
49 +async function pollUntilConfirmed(paymentId: string): Promise<string | undefined> {
50 + const INTERVAL_MS = 15_000;
51 + const MAX_ATTEMPTS = 40; // ~10 minutes
52 +
53 + for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt++) {
54 + const result = await wallet.watchPayment(paymentId);
55 +
56 + if (result.confirmed) {
57 + console.log('Transaction confirmed:', result.transaction_hash);
58 + return result.transaction_hash;
59 + }
60 +
61 + console.log(`Attempt ${attempt + 1}: not yet confirmed. Retrying...`);
62 + await new Promise(resolve => setTimeout(resolve, INTERVAL_MS));
63 + }
64 +
65 + console.warn('Payment not confirmed within polling window.');
66 + return undefined;
67 +}
68 +
69 +const txHash = await pollUntilConfirmed('pay_xyz789');
70 +```
71 +
72 +```bash cURL
73 +curl -X GET \
74 + https://api.procurenet.io/mods/procurement_wallet/usdc/watch/pay_xyz789 \
75 + -H "x-perplexity-mod-key: $PROCURENET_MOD_KEY"
76 +```
77 +</CodeGroup>
78 +
79 +## Response
80 +
81 +<ResponseField name="confirmed" type="boolean" required>
82 + `true` when the on-chain transaction has been detected and confirmed. `false` if the payment is still pending or has expired without a matching transfer.
83 +</ResponseField>
84 +
85 +<ResponseField name="transaction_hash" type="string">
86 + The blockchain transaction hash for the confirmed transfer. This field is only present when `confirmed` is `true`. Store this value for auditing and reconciliation.
87 +</ResponseField>
88 +
89 +### Example Response — Pending
90 +
91 +```json
92 +{
93 + "confirmed": false
94 +}
95 +```
96 +
97 +### Example Response — Confirmed
98 +
99 +```json
100 +{
101 + "confirmed": true,
102 + "transaction_hash": "0x4f3c8b2a1e9d7f6c0b5a4e3d2c1b0a9f8e7d6c5b4a3f2e1d0c9b8a7f6e5d4c3b"
103 +}
104 +```
105 +
106 +## Expired Payments
107 +
108 +<Warning>
109 + If a payment request expires before the transfer is confirmed, this endpoint returns `"confirmed": false` with no `transaction_hash`. The payment request cannot be reactivated. Create a new payment request via [`POST /usdc/request`](/api/usdc-request) and restart the confirmation flow.
110 +</Warning>
111 +
112 +## Error Codes
113 +
114 +| Status | Meaning |
115 +|---|---|
116 +| `401` | Missing or invalid `x-perplexity-mod-key` header |
117 +| `404` | No payment found for the given `paymentId` |
118 +
119 +<Tip>
120 + Once you receive `"confirmed": true`, update your internal records immediately. The `VCIProcureNetBridge` writes `status: "payment_confirmed"` and `tx_hash` back to the queue record automatically when using the bridge's built-in watch flow.
121 +</Tip>
api/webhook-procurement.mdx new
+221
@@ -0,0 +1,221 @@
1 +---
2 +title: "POST /webhooks/procurement — Approval Callback"
3 +sidebarTitle: "POST /webhooks"
4 +description: "Handle signed Procurement Express approval webhooks. Approved decisions resume sessions; rejected ones terminate them. Always verify the HMAC signature."
5 +---
6 +
7 +ProcureNet sends a signed POST request to your webhook URL whenever a Procurement Express approval decision is made. Your handler receives a payload containing a `session_id`, a `decision` of either `approved` or `rejected`, the `actor` who made the decision, and an optional `reason`. Before acting on the payload, you must verify the `x-procure-signature` header using your shared webhook secret — requests that fail signature verification must be rejected to prevent spoofed approvals from influencing live procurement sessions. Return HTTP `204` on success; ProcureNet will retry on any non-`2xx` response.
8 +
9 +## Endpoint
10 +
11 +```http
12 +POST /webhooks/procurement
13 +```
14 +
15 +## Authentication
16 +
17 +ProcureNet signs each outbound webhook request with an HMAC-SHA256 signature derived from your shared secret and the raw request body. The signature arrives in the `x-procure-signature` header in the format:
18 +
19 +```text
20 +x-procure-signature: sha256=<hex_digest>
21 +```
22 +
23 +Your handler must recompute the expected signature and compare it to the header value **before** parsing or acting on the payload.
24 +
25 +<Warning>
26 + Always parse the request body using `express.raw()` (or equivalent raw body middleware) **before** performing signature verification. If you parse the body as JSON first, the serialization may differ from what ProcureNet signed, causing every verification to fail regardless of key validity.
27 +</Warning>
28 +
29 +## Signature Verification
30 +
31 +<Steps>
32 + <Step title="Receive the raw request body">
33 + Configure your route to buffer the raw bytes of the request body. In Express, use `express.raw({ type: 'application/json' })` on the webhook route — do not apply `express.json()` globally before this route.
34 + </Step>
35 + <Step title="Read the x-procure-signature header">
36 + Extract the `x-procure-signature` header from the incoming request. If the header is absent, reject the request immediately with `401`.
37 + </Step>
38 + <Step title="Recompute the expected signature">
39 + Use HMAC-SHA256 with your `WEBHOOK_SECRET` and the raw request body buffer to compute the expected digest. Prepend `sha256=` to match the header format.
40 + </Step>
41 + <Step title="Compare signatures">
42 + Compare the computed signature to the header value. Use a constant-time comparison where possible to avoid timing attacks. Reject with `401` on mismatch.
43 + </Step>
44 + <Step title="Parse and handle the payload">
45 + Parse the raw body as JSON only after verification passes. Act on the `decision` field and return `204`.
46 + </Step>
47 +</Steps>
48 +
49 +## Code Example
50 +
51 +<CodeGroup>
52 +```typescript Express (TypeScript)
53 +import express from 'express';
54 +import { createHmac } from 'crypto';
55 +
56 +const app = express();
57 +
58 +app.post(
59 + '/webhooks/procurement',
60 + express.raw({ type: 'application/json' }),
61 + (req, res) => {
62 + const signature = req.headers['x-procure-signature'] as string;
63 +
64 + if (!signature) {
65 + return res.status(401).send('Missing signature');
66 + }
67 +
68 + const expected =
69 + 'sha256=' +
70 + createHmac('sha256', process.env.WEBHOOK_SECRET!)
71 + .update(req.body)
72 + .digest('hex');
73 +
74 + if (signature !== expected) {
75 + return res.status(401).send('Invalid signature');
76 + }
77 +
78 + const payload = JSON.parse(req.body.toString()) as {
79 + session_id: string;
80 + decision: 'approved' | 'rejected';
81 + actor: string;
82 + reason?: string;
83 + };
84 +
85 + if (payload.decision === 'approved') {
86 + // Resume the suspended orchestration flow for this session
87 + console.log(`Session ${payload.session_id} approved by ${payload.actor}`);
88 + } else {
89 + // Terminate the session
90 + console.log(`Session ${payload.session_id} rejected: ${payload.reason ?? 'no reason given'}`);
91 + }
92 +
93 + return res.status(204).send();
94 + }
95 +);
96 +```
97 +
98 +```typescript Next.js API Route
99 +import { createHmac } from 'crypto';
100 +import type { NextApiRequest, NextApiResponse } from 'next';
101 +
102 +export const config = {
103 + api: { bodyParser: false },
104 +};
105 +
106 +async function getRawBody(req: NextApiRequest): Promise<Buffer> {
107 + return new Promise((resolve, reject) => {
108 + const chunks: Buffer[] = [];
109 + req.on('data', chunk => chunks.push(chunk));
110 + req.on('end', () => resolve(Buffer.concat(chunks)));
111 + req.on('error', reject);
112 + });
113 +}
114 +
115 +export default async function handler(req: NextApiRequest, res: NextApiResponse) {
116 + if (req.method !== 'POST') {
117 + return res.status(405).end();
118 + }
119 +
120 + const rawBody = await getRawBody(req);
121 + const signature = req.headers['x-procure-signature'] as string;
122 + const expected =
123 + 'sha256=' +
124 + createHmac('sha256', process.env.WEBHOOK_SECRET!)
125 + .update(rawBody)
126 + .digest('hex');
127 +
128 + if (signature !== expected) {
129 + return res.status(401).json({ error: 'Invalid signature' });
130 + }
131 +
132 + const payload = JSON.parse(rawBody.toString());
133 +
134 + // Handle approved / rejected
135 + if (payload.decision === 'approved') {
136 + await resumeSession(payload.session_id);
137 + } else {
138 + await terminateSession(payload.session_id, payload.reason);
139 + }
140 +
141 + return res.status(204).end();
142 +}
143 +```
144 +</CodeGroup>
145 +
146 +## Payload Fields
147 +
148 +<ParamField body="session_id" type="string" required>
149 + The ProcureNet session ID that this approval decision applies to. Use this to look up the suspended session in your orchestration state.
150 +</ParamField>
151 +
152 +<ParamField body="decision" type="string" required>
153 + The approval outcome. One of:
154 + - `"approved"` — the session should be resumed and the procurement flow continued.
155 + - `"rejected"` — the session should be terminated and any reserved resources released.
156 +</ParamField>
157 +
158 +<ParamField body="actor" type="string" required>
159 + The identity of the person or system that made the approval decision. This value is provided by Procurement Express and may be an email address, username, or system identifier depending on your Procurement Express configuration.
160 +</ParamField>
161 +
162 +<ParamField body="reason" type="string">
163 + An optional human-readable explanation for the decision. This is most commonly populated for `rejected` decisions to explain why a session was not approved. Log this value for auditing purposes.
164 +</ParamField>
165 +
166 +### Example Payload — Approved
167 +
168 +```json
169 +{
170 + "session_id": "sess_a1b2c3d4",
171 + "decision": "approved",
172 + "actor": "procurement-manager@example.com",
173 + "reason": "Budget confirmed for Q3 vendor onboarding"
174 +}
175 +```
176 +
177 +### Example Payload — Rejected
178 +
179 +```json
180 +{
181 + "session_id": "sess_e5f6g7h8",
182 + "decision": "rejected",
183 + "actor": "compliance-bot",
184 + "reason": "Vendor not on approved supplier list"
185 +}
186 +```
187 +
188 +## Response
189 +
190 +Return HTTP `204 No Content` to acknowledge the webhook. Do not return a body.
191 +
192 +| Status | Meaning |
193 +|---|---|
194 +| `204` | Webhook received and processed successfully |
195 +| `401` | Signature verification failed — request rejected |
196 +
197 +<Note>
198 + ProcureNet retries webhook delivery on any non-`2xx` response using an exponential back-off policy. Make your handler idempotent — the same `session_id` + `decision` combination may arrive more than once. Check whether the session is already in its target state before applying side effects.
199 +</Note>
200 +
201 +## Decision Handling
202 +
203 +<CardGroup cols={2}>
204 + <Card title="approved" icon="circle-check">
205 + Resume the suspended orchestration flow. The session re-enters the state machine at the point it was paused. You may want to call `POST /api/v7/sessions/{id}/transition` to advance to the next state after resuming.
206 + </Card>
207 + <Card title="rejected" icon="circle-xmark">
208 + Terminate the session immediately. Release any held inventory or funding reservations, notify the buyer, and close the session. Log the `actor` and `reason` fields for your audit trail.
209 + </Card>
210 +</CardGroup>
211 +
212 +## Security Checklist
213 +
214 +<Accordion title="Webhook security best practices">
215 + - **Never skip signature verification.** Even in development, always verify the `x-procure-signature` header.
216 + - **Use a raw body parser.** Applying a JSON parser before verification will invalidate the HMAC check.
217 + - **Store `WEBHOOK_SECRET` securely.** Treat this secret like a private key — use environment variables or a secrets manager, never hardcode it.
218 + - **Make handlers idempotent.** ProcureNet may deliver the same event more than once. Guard against double-processing by checking current session state before applying transitions.
219 + - **Respond promptly.** Complete signature verification and enqueue any heavy work asynchronously. Return `204` within a few seconds to avoid triggering ProcureNet's retry logic.
220 + - **Log all decisions.** Store the full payload, `actor`, and timestamp for each webhook received. Approval decisions are auditable events.
221 +</Accordion>
authentication.mdx new
+248
@@ -0,0 +1,248 @@
1 +---
2 +title: "How to Authenticate Every Request to ProcureNet APIs"
3 +sidebarTitle: "Authentication"
4 +description: "ProcureNet uses four credential types — mod keys, JWT bearer tokens, webhook HMAC signatures, and admin keys — each scoped to a specific part of the API."
5 +---
6 +
7 +ProcureNet authenticates requests through four distinct mechanisms, each scoped to a different surface of the API. Wallet and payment endpoints use a mod key passed as a custom header. Session endpoints require a JWT bearer token. Inbound webhooks from Procurement Express carry an HMAC signature you must verify before processing. Admin override endpoints require a separate admin key. Understanding which credential applies where prevents auth failures and keeps your integration secure.
8 +
9 +---
10 +
11 +## API Keys (Wallet and Payment Endpoints)
12 +
13 +Wallet and payment endpoints authenticate with a **mod key** passed in the `x-perplexity-mod-key` header. You receive this key from the ProcureNet dashboard when you create a workspace. Use it on all requests to the USDC payment bridge:
14 +
15 +- `POST /mods/procurement_wallet/usdc/request` — create a USDC payment request
16 +- `GET /mods/procurement_wallet/usdc/watch/{paymentId}` — poll for payment confirmation
17 +
18 +```typescript
19 +const response = await fetch(
20 + `${process.env.PROCURENET_BASE_URL}/mods/procurement_wallet/usdc/request`,
21 + {
22 + method: "POST",
23 + headers: {
24 + "Content-Type": "application/json",
25 + "x-perplexity-mod-key": process.env.PROCURENET_MOD_KEY!,
26 + },
27 + body: JSON.stringify({
28 + tenant_id: "your-tenant-id",
29 + amount_usdc: 250,
30 + network: "base",
31 + token: "USDC",
32 + memo: "Evaluation payout — Assignment #A-1042",
33 + metadata: {
34 + evaluator_id: "eval_0192XZ",
35 + assignment_id: "A-1042",
36 + },
37 + }),
38 + }
39 +);
40 +
41 +const payment = await response.json();
42 +// { payment_id, deposit_address, qr_code, expires_at }
43 +```
44 +
45 +<Note>
46 + Your mod key carries full access to the wallet API. Never embed it in client-side code, browser bundles, or public repositories. Always load it from a server-side environment variable.
47 +</Note>
48 +
49 +---
50 +
51 +## JWT Bearer Tokens (Session Endpoints)
52 +
53 +Session endpoints require a **JWT bearer token** in the standard `Authorization` header. You receive a JWT after authenticating with ProcureNet's identity service (consult your onboarding docs for the token exchange flow specific to your setup). Pass this token on every request to the following endpoints:
54 +
55 +| Endpoint | Method | Purpose |
56 +|---|---|---|
57 +| `/api/v7/sessions/{id}/prefill` | GET | Retrieve prefill data for resolved sessions |
58 +| `/api/v7/sessions/{id}/transition` | POST | Advance the session state machine |
59 +| `/api/v7/sessions/{id}/escrow-accept` | POST | Accept escrow for high-value transactions |
60 +| `/api/v7/sessions/{id}/funding-method` | POST | Set the payment method on a session |
61 +
62 +```typescript
63 +const sessionId = "sess_01JKAB3MXPQ7RVTZWN5";
64 +
65 +// Retrieve prefill data (resolved sessions only — WCS ≥ 100)
66 +const prefillResponse = await fetch(
67 + `${process.env.PROCURENET_BASE_URL}/api/v7/sessions/${sessionId}/prefill`,
68 + {
69 + method: "GET",
70 + headers: {
71 + Authorization: `Bearer ${process.env.PROCURENET_JWT}`,
72 + },
73 + }
74 +);
75 +
76 +const prefill = await prefillResponse.json();
77 +// { customer: { ... }, payment_preferences: [...] }
78 +```
79 +
80 +```typescript
81 +// Set a funding method on the session
82 +const fundingResponse = await fetch(
83 + `${process.env.PROCURENET_BASE_URL}/api/v7/sessions/${sessionId}/funding-method`,
84 + {
85 + method: "POST",
86 + headers: {
87 + "Content-Type": "application/json",
88 + Authorization: `Bearer ${process.env.PROCURENET_JWT}`,
89 + },
90 + body: JSON.stringify({
91 + method: "card",
92 + token: "pm_card_visa_deferred",
93 + }),
94 + }
95 +);
96 +```
97 +
98 +<Tip>
99 + JWTs are scoped to the session they were issued for. Passing a token from session A on a request for session B returns a `403 Forbidden` response.
100 +</Tip>
101 +
102 +---
103 +
104 +## Webhook Signature Verification
105 +
106 +When Procurement Express sends an approval callback to your `POST /webhooks/procurement` endpoint, it includes an HMAC signature in the `x-procure-signature` header. You **must** verify this signature before processing the payload — unverified webhooks can be spoofed by any party that knows your endpoint URL.
107 +
108 +Verification works by computing an HMAC-SHA256 digest of the raw request body using your webhook secret, then comparing it to the value in `x-procure-signature`. Use a constant-time comparison to avoid timing attacks.
109 +
110 +```typescript
111 +import { createHmac, timingSafeEqual } from "crypto";
112 +import type { IncomingMessage, ServerResponse } from "http";
113 +
114 +function verifyProcureSignature(
115 + rawBody: Buffer,
116 + signatureHeader: string,
117 + secret: string
118 +): boolean {
119 + const expected = createHmac("sha256", secret)
120 + .update(rawBody)
121 + .digest("hex");
122 +
123 + const expectedBuf = Buffer.from(expected, "utf8");
124 + const receivedBuf = Buffer.from(signatureHeader, "utf8");
125 +
126 + // Buffers must be the same length before timingSafeEqual
127 + if (expectedBuf.length !== receivedBuf.length) {
128 + return false;
129 + }
130 +
131 + return timingSafeEqual(expectedBuf, receivedBuf);
132 +}
133 +
134 +// Example Express handler
135 +app.post(
136 + "/webhooks/procurement",
137 + express.raw({ type: "application/json" }),
138 + (req: IncomingMessage & { body: Buffer }, res: ServerResponse) => {
139 + const signature = req.headers["x-procure-signature"] as string;
140 +
141 + if (!signature) {
142 + res.writeHead(400);
143 + res.end("Missing signature");
144 + return;
145 + }
146 +
147 + const isValid = verifyProcureSignature(
148 + req.body,
149 + signature,
150 + process.env.PROCURENET_WEBHOOK_SECRET!
151 + );
152 +
153 + if (!isValid) {
154 + res.writeHead(401);
155 + res.end("Invalid signature");
156 + return;
157 + }
158 +
159 + const payload = JSON.parse(req.body.toString());
160 + // payload: { session_id, decision: "approved" | "rejected", actor, reason? }
161 + console.log("Procurement approval received:", payload);
162 +
163 + res.writeHead(204);
164 + res.end();
165 + }
166 +);
167 +```
168 +
169 +<Warning>
170 + Always read the raw request body **before** any JSON parsing middleware runs. If your framework parses the body into an object first, re-serializing it can change whitespace and break the HMAC digest, causing all verification checks to fail.
171 +</Warning>
172 +
173 +---
174 +
175 +## Admin Keys
176 +
177 +The `x-admin-key` header is required for manual payment confirmation at `POST /mods/procurement_wallet/usdc/manual-confirm`. This endpoint exists for operational overrides — for example, when an on-chain confirmation is delayed and you need to unblock a field evaluator's payout manually.
178 +
179 +Pass both your mod key and your admin key together on this request:
180 +
181 +```typescript
182 +const confirmResponse = await fetch(
183 + `${process.env.PROCURENET_BASE_URL}/mods/procurement_wallet/usdc/manual-confirm`,
184 + {
185 + method: "POST",
186 + headers: {
187 + "Content-Type": "application/json",
188 + "x-perplexity-mod-key": process.env.PROCURENET_MOD_KEY!,
189 + "x-admin-key": process.env.PROCURENET_ADMIN_KEY!,
190 + },
191 + body: JSON.stringify({
192 + payment_id: "pay_01HXYZ77BBQRST",
193 + }),
194 + }
195 +);
196 +
197 +const result = await confirmResponse.json();
198 +// { confirmed: true, transaction_hash: "0xabc..." }
199 +```
200 +
201 +<Warning>
202 + Admin keys grant override authority over payment confirmation. Treat them with the same security rigor as private keys — restrict access to server-side infrastructure only, rotate them immediately if exposed, and audit their use through your logging pipeline.
203 +</Warning>
204 +
205 +---
206 +
207 +## Error Reference
208 +
209 +When authentication fails, ProcureNet returns one of the following HTTP status codes:
210 +
211 +| Status | Meaning | Common Causes |
212 +|---|---|---|
213 +| `401 Unauthorized` | Missing or invalid credential | No `Authorization` header, expired JWT, malformed mod key, failed HMAC verification |
214 +| `403 Forbidden` | Valid credential but insufficient access | JWT scoped to a different session, prefill requested on a non-resolved session (WCS &lt; 100), admin endpoint called without `x-admin-key` |
215 +| `429 Too Many Requests` | Rate limit exceeded | Too many requests in a short window; back off and retry with exponential delay |
216 +
217 +<Accordion title="Handling 401 vs 403 in your client">
218 + A `401` means the credential itself is unrecognized or malformed — check that you're sending the right header name, that the token hasn't expired, and that you haven't accidentally URL-encoded the value.
219 +
220 + A `403` means ProcureNet recognized your credential but the specific action is not permitted. The most common cause is calling `GET /api/v7/sessions/{id}/prefill` on a session with a WCS score below 100. Check the `mode` field from your original orchestration response before attempting prefill.
221 +</Accordion>
222 +
223 +---
224 +
225 +## Credential Summary
226 +
227 +<CardGroup cols={2}>
228 + <Card title="x-perplexity-mod-key" icon="key">
229 + **Scope:** Wallet and USDC payment endpoints
230 + **Where to get it:** ProcureNet dashboard
231 + **Never expose:** client-side code or public repos
232 + </Card>
233 + <Card title="Authorization: Bearer JWT" icon="id-badge">
234 + **Scope:** All `/api/v7/sessions/{id}/...` endpoints
235 + **Where to get it:** ProcureNet identity service token exchange
236 + **Scoped to:** individual sessions
237 + </Card>
238 + <Card title="x-procure-signature" icon="shield-check">
239 + **Scope:** Inbound webhook verification
240 + **Where to get it:** ProcureNet dashboard (webhook secret)
241 + **Direction:** Inbound — you verify it, not send it
242 + </Card>
243 + <Card title="x-admin-key" icon="shield-halved">
244 + **Scope:** Manual payment confirmation only
245 + **Where to get it:** ProcureNet account team
246 + **Never expose:** client-side code, logs, or public repos
247 + </Card>
248 +</CardGroup>
concepts/orchestration-modes.mdx new
+104
@@ -0,0 +1,104 @@
1 +---
2 +title: "Orchestration Modes: Resolved, Partial, Anonymous"
3 +sidebarTitle: "Modes"
4 +description: "Explore how ProcureNet's three orchestration modes shape the checkout experience, transport protocol, and available prefill data for each session."
5 +---
6 +
7 +Orchestration modes define the capabilities and experience of a checkout session. ProcureNet assigns a mode to every session at creation time, derived directly from the buyer's [Wallet Confidence Score (WCS)](/concepts/wallet-confidence-score). The mode is fixed for the lifetime of that session — it determines which real-time transport protocol to use, whether prefill data is available, and how much information the buyer will need to provide manually. Choosing which signals to supply at orchestration time is therefore the most important decision you make when starting a procurement flow.
8 +
9 +## Resolved Mode (WCS ≥ 100)
10 +
11 +Resolved mode activates when ProcureNet has high confidence in the buyer's identity — typically when a `customerId` is present. This is the premium checkout experience.
12 +
13 +<CardGroup cols={2}>
14 + <Card title="Transport" icon="signal-stream">
15 + **Server-Sent Events (SSE)** — a lightweight, unidirectional stream that delivers session events with minimal overhead.
16 + </Card>
17 + <Card title="Prefill" icon="wand-magic-sparkles">
18 + **Available** — call `GET /api/v7/sessions/{id}/prefill` to retrieve the customer's saved profile and payment preferences. Requires a Bearer JWT.
19 + </Card>
20 +</CardGroup>
21 +
22 +In resolved mode, ProcureNet pre-populates checkout fields using the buyer's stored data, reducing friction to near zero for returning customers. The prefill endpoint returns structured profile and payment-preference objects that your UI can apply directly.
23 +
24 +```bash
25 +curl https://api.procurenet.io/api/v7/sessions/sess_abc/prefill \
26 + -H "Authorization: Bearer <JWT>"
27 +```
28 +
29 +## Partial Mode (WCS 40–99)
30 +
31 +Partial mode activates when ProcureNet recognizes some signals — such as an email or phone number — but lacks a confirmed customer identity. The session proceeds interactively.
32 +
33 +<CardGroup cols={2}>
34 + <Card title="Transport" icon="arrows-rotate">
35 + **WebSocket** — a full-duplex channel that supports both sending and receiving messages, suitable for guided multi-step flows.
36 + </Card>
37 + <Card title="Prefill" icon="ban">
38 + **Not available** — the buyer must supply any missing identity and payment information during the session.
39 + </Card>
40 +</CardGroup>
41 +
42 +In partial mode, your UI should guide the buyer through completing their profile. Collecting a `customerId` during this flow and using it in a new session will upgrade the experience to resolved mode.
43 +
44 +## Anonymous Mode (WCS < 40)
45 +
46 +Anonymous mode activates when ProcureNet has no reliable signals about the buyer. This covers guest checkouts and first-time visitors.
47 +
48 +<CardGroup cols={2}>
49 + <Card title="Transport" icon="arrows-rotate">
50 + **WebSocket** — same bidirectional channel as partial mode, supporting the full interactive checkout flow.
51 + </Card>
52 + <Card title="Prefill" icon="ban">
53 + **Not available** — the buyer completes the full checkout form from scratch, with no prior data applied.
54 + </Card>
55 +</CardGroup>
56 +
57 +Anonymous mode imposes no restrictions on transaction completion — it simply means more manual input is required. Consider prompting buyers to create an account during or after checkout so future sessions benefit from a higher WCS.
58 +
59 +## Connecting to the Transport
60 +
61 +Once you have a `session_id` and know the `transport` from the `POST /api/v7/orchestrate` response, open the appropriate real-time connection.
62 +
63 +<Tabs>
64 + <Tab title="SSE (Resolved)">
65 + Server-Sent Events are native to the browser. Open the stream with `EventSource` and listen for named session events.
66 +
67 + ```javascript
68 + const source = new EventSource('/api/v7/sessions/sess_abc/stream');
69 +
70 + source.addEventListener('state_change', (event) => {
71 + const data = JSON.parse(event.data);
72 + console.log('New state:', data.state);
73 + });
74 +
75 + source.addEventListener('error', () => {
76 + source.close();
77 + });
78 + ```
79 + </Tab>
80 + <Tab title="WebSocket (Partial / Anonymous)">
81 + WebSocket provides full-duplex communication. Use the secure `wss://` scheme in production.
82 +
83 + ```javascript
84 + const ws = new WebSocket('wss://api.procurenet.io/api/v7/sessions/sess_abc/ws');
85 +
86 + ws.onopen = () => {
87 + console.log('Session channel open');
88 + };
89 +
90 + ws.onmessage = (event) => {
91 + const data = JSON.parse(event.data);
92 + console.log('Session event:', data);
93 + };
94 +
95 + ws.onerror = (error) => {
96 + console.error('WebSocket error:', error);
97 + };
98 + ```
99 + </Tab>
100 +</Tabs>
101 +
102 +<Tip>
103 + Upgrading a session from anonymous or partial to resolved is not possible in-place. To give a buyer the resolved experience after collecting additional signals mid-flow, create a new session via `POST /api/v7/orchestrate` and pass the newly gathered signals in the `hints` object. The new session will receive the higher WCS and switch to SSE automatically.
104 +</Tip>
concepts/payment-settlement.mdx new
+107
@@ -0,0 +1,107 @@
1 +---
2 +title: "USDC Payment Settlement on EVM Networks"
3 +sidebarTitle: "Payment Settlement"
4 +description: "Learn how ProcureNet settles payments in USDC across Base, Arbitrum, Polygon, and Ethereum, including field evaluator payout tiers."
5 +---
6 +
7 +ProcureNet settles payments in USDC stablecoins on EVM-compatible networks. Whether you are integrating a buyer-facing checkout, running a procurement workflow, or disbursing payments to field evaluators, every payment follows the same on-chain settlement path: a payment request is created, a deposit address is shared with the payer, and the system watches for confirmation before releasing funds. This approach ensures deterministic, auditable settlement without reliance on traditional payment rails.
8 +
9 +## Supported Networks
10 +
11 +You can settle payments on any of the following EVM networks. Specify the network when creating a payment request.
12 +
13 +<CardGroup cols={2}>
14 + <Card title="Base" icon="circle-b">
15 + Low fees and fast finality. Recommended for high-volume procurement flows.
16 + </Card>
17 + <Card title="Arbitrum" icon="circle-a">
18 + Layer-2 rollup on Ethereum with low transaction costs and broad wallet support.
19 + </Card>
20 + <Card title="Polygon" icon="hexagon-check">
21 + Widely supported, low-cost EVM network with mature tooling.
22 + </Card>
23 + <Card title="Ethereum" icon="ethereum">
24 + The canonical EVM mainnet. Use when counterparties require settlement on L1.
25 + </Card>
26 +</CardGroup>
27 +
28 +## Payment Flow
29 +
30 +Follow these steps to create and confirm a USDC payment.
31 +
32 +<Steps>
33 + <Step title="Create a payment request">
34 + Call `POST /mods/procurement_wallet/usdc/request` with the amount, network, and any evaluation metadata. Authenticate using your `x-perplexity-mod-key` header.
35 +
36 + ```bash
37 + curl -X POST https://api.procurenet.io/mods/procurement_wallet/usdc/request \
38 + -H "x-perplexity-mod-key: <api_key>" \
39 + -H "Content-Type: application/json" \
40 + -d '{
41 + "amount": 250,
42 + "network": "base",
43 + "currency": "USDC",
44 + "recipient": "0xYourWalletAddress"
45 + }'
46 + ```
47 +
48 + The response includes a `payment_id`, `deposit_address`, `qr_code`, and `expires_at` timestamp.
49 + </Step>
50 +
51 + <Step title="Share the deposit address with the payer">
52 + Display the `deposit_address` or render the `qr_code` in your UI. The payer sends USDC to this address on the specified network. No additional API call is needed at this stage — ProcureNet monitors the address automatically.
53 + </Step>
54 +
55 + <Step title="Watch for confirmation">
56 + Poll `GET /mods/procurement_wallet/usdc/watch/{paymentId}` to check settlement status. The endpoint returns the current confirmation state and, once confirmed, a `transaction_hash`.
57 +
58 + ```bash
59 + curl https://api.procurenet.io/mods/procurement_wallet/usdc/watch/pay_xyz \
60 + -H "x-perplexity-mod-key: <api_key>"
61 + ```
62 +
63 + Continue polling until the response status is `confirmed`. Implement exponential backoff — most networks confirm within seconds on Base and Arbitrum, and within minutes on Ethereum mainnet.
64 + </Step>
65 +
66 + <Step title="Receive the transaction hash">
67 + On confirmation, the watch endpoint returns a `transaction_hash`. Store this value as your permanent, on-chain proof of settlement. It can be verified independently on any EVM block explorer for the target network.
68 + </Step>
69 +</Steps>
70 +
71 +<Info>
72 + Each payment request carries an `expires_at` timestamp. If the payer has not sent funds before that time, the request expires and cannot be confirmed. Create a new payment request and share the updated `deposit_address` with the payer.
73 +</Info>
74 +
75 +## VCI Field Evaluator Payment Tiers
76 +
77 +For field evaluation workflows, ProcureNet calculates the USDC payout automatically based on the evaluator's average quality score. You do not need to specify an amount manually — pass the evaluation results when creating the payment request and the bridge applies the correct tier.
78 +
79 +<Note>
80 + Payments for field evaluations include GPS metadata from the evaluator's device when location data is available at sync time. This metadata is stored alongside the transaction record for audit purposes.
81 +</Note>
82 +
83 +| Average Evaluation Score | USDC Payout |
84 +|---|---|
85 +| ≥ 9.0 | 500 USDC |
86 +| ≥ 7.0 | 250 USDC |
87 +| ≥ 5.0 | 100 USDC |
88 +| < 5.0 | 0 USDC |
89 +
90 +<Accordion title="How the tier is calculated">
91 + The VCI bridge averages all evaluation scores submitted in a sync batch. If an evaluator submits five evaluations with scores of 8.5, 9.2, 7.8, 8.0, and 9.5, their average is 8.6 — which falls into the ≥ 7.0 tier and triggers a 250 USDC payout. The bridge computes this automatically; no manual tier selection is exposed via the API.
92 +</Accordion>
93 +
94 +## Admin Manual Confirmation
95 +
96 +In exceptional cases — such as on-chain delays or network congestion — an administrator can manually confirm a payment using `POST /mods/procurement_wallet/usdc/manual-confirm`. This endpoint requires an `x-admin-key` header and should only be used when automated confirmation has stalled.
97 +
98 +```bash
99 +curl -X POST https://api.procurenet.io/mods/procurement_wallet/usdc/manual-confirm \
100 + -H "x-admin-key: <admin_key>" \
101 + -H "Content-Type: application/json" \
102 + -d '{ "payment_id": "pay_xyz", "transaction_hash": "0xabc..." }'
103 +```
104 +
105 +<Warning>
106 + Manual confirmation bypasses on-chain verification. Only use this endpoint when you have independently verified the transaction on a block explorer and are certain the funds have arrived. Misuse can result in double-confirmation or incorrect payout records.
107 +</Warning>
concepts/session-lifecycle.mdx new
+105
@@ -0,0 +1,105 @@
1 +---
2 +title: "ProcureNet Session Lifecycle and State Machine"
3 +sidebarTitle: "Session Lifecycle"
4 +description: "Understand how ProcureNet sessions progress through states from creation to completion, and how to drive each transition correctly."
5 +---
6 +
7 +Sessions are the core unit of a ProcureNet procurement flow. Every buyer interaction — from the moment checkout begins to the final payment confirmation — is tracked inside a single session object. Each session moves through a well-defined state machine: states advance in a fixed order, illegal transitions are rejected with deterministic error codes, and every successful transition emits a real-time event over the session's transport channel. Understanding the lifecycle helps you build reliable integrations that handle retries, timeouts, and escrow correctly.
8 +
9 +## Session States
10 +
11 +A session passes through the following states in order. Not every session visits every state — the `escrow_pending` state only applies to high-value transactions.
12 +
13 +<CardGroup cols={2}>
14 + <Card title="created" icon="circle-plus">
15 + The session has been initialized by `POST /api/v7/orchestrate`. The WCS score, mode, and transport have been assigned. No payment data has been provided yet.
16 + </Card>
17 + <Card title="active" icon="circle-play">
18 + The buyer's transport connection has been established (SSE or WebSocket). The session is live and accepting input.
19 + </Card>
20 + <Card title="funded" icon="circle-dollar-sign">
21 + A funding method has been successfully set via `POST /api/v7/sessions/{id}/funding-method`. The session is ready to proceed to completion or escrow.
22 + </Card>
23 + <Card title="escrow_pending" icon="lock">
24 + For high-value transactions only. Escrow has been initiated and is awaiting acceptance via `POST /api/v7/sessions/{id}/escrow-accept`.
25 + </Card>
26 + <Card title="completed" icon="circle-check">
27 + The procurement flow finished successfully. The session is now immutable.
28 + </Card>
29 + <Card title="cancelled" icon="circle-xmark">
30 + The session was cancelled before completion. No charges were processed.
31 + </Card>
32 +</CardGroup>
33 +
34 +<Note>
35 + Illegal state transitions — such as attempting to accept escrow on a session that is not yet funded — are rejected synchronously with a deterministic error code in the response body. Build your integration to check for these codes rather than relying on HTTP status alone.
36 +</Note>
37 +
38 +## Driving a Session Through Its Lifecycle
39 +
40 +Follow these steps to move a session from creation to completion.
41 +
42 +<Steps>
43 + <Step title="Create the session">
44 + Call `POST /api/v7/orchestrate` with your buyer signals in the `hints` object. The response returns a `session_id`, `wcs_score`, `mode`, and `transport`. Store the `session_id` — every subsequent call requires it.
45 +
46 + ```bash
47 + curl -X POST https://api.procurenet.io/api/v7/orchestrate \
48 + -H "Authorization: Bearer <JWT>" \
49 + -H "Content-Type: application/json" \
50 + -d '{
51 + "hints": {
52 + "customerId": "cust_123",
53 + "email": "buyer@example.com"
54 + }
55 + }'
56 + ```
57 + </Step>
58 +
59 + <Step title="Connect to the real-time transport">
60 + Use the `transport` value from the response to open the correct channel. Resolved sessions use SSE; partial and anonymous sessions use WebSocket. See [Orchestration Modes](/concepts/orchestration-modes) for connection examples.
61 + </Step>
62 +
63 + <Step title="Set the funding method">
64 + Call `POST /api/v7/sessions/{id}/funding-method` with the buyer's chosen payment method. This advances the session from `active` to `funded`.
65 +
66 + ```bash
67 + curl -X POST https://api.procurenet.io/api/v7/sessions/sess_abc/funding-method \
68 + -H "Authorization: Bearer <JWT>" \
69 + -H "Content-Type: application/json" \
70 + -d '{ "method": "usdc", "network": "base" }'
71 + ```
72 + </Step>
73 +
74 + <Step title="Accept escrow (high-value transactions only)">
75 + If the transaction value exceeds the escrow threshold, the session enters `escrow_pending`. Call `POST /api/v7/sessions/{id}/escrow-accept` to acknowledge the escrow terms and advance the session.
76 +
77 + ```bash
78 + curl -X POST https://api.procurenet.io/api/v7/sessions/sess_abc/escrow-accept \
79 + -H "Authorization: Bearer <JWT>"
80 + ```
81 + </Step>
82 +
83 + <Step title="Advance to completion">
84 + Call `POST /api/v7/sessions/{id}/transition` to move the session toward `completed`. You may need to call this endpoint more than once if your flow has intermediate steps — each call advances the state machine by one step.
85 +
86 + ```bash
87 + curl -X POST https://api.procurenet.io/api/v7/sessions/sess_abc/transition \
88 + -H "Authorization: Bearer <JWT>" \
89 + -H "Content-Type: application/json" \
90 + -d '{ "action": "confirm" }'
91 + ```
92 + </Step>
93 +</Steps>
94 +
95 +## Session Expiry
96 +
97 +Sessions have a finite lifetime. If a session expires before you complete all transitions, any further API calls against that session ID return **410 Gone**. When you receive a 410, you must create a new session from scratch — expired sessions cannot be resumed or extended.
98 +
99 +<Warning>
100 + Do not cache session IDs across user visits or browser reloads without validating that the session is still active. Always check for 410 responses and handle them by restarting orchestration.
101 +</Warning>
102 +
103 +<Tip>
104 + Every state transition emits an event over the session's transport channel. Subscribe to these events in your UI to drive real-time progress indicators without polling the API.
105 +</Tip>
concepts/wallet-confidence-score.mdx new
+70
@@ -0,0 +1,70 @@
1 +---
2 +title: "What Is the Wallet Confidence Score?"
3 +sidebarTitle: "WCS"
4 +description: "Learn how ProcureNet scores buyer identity signals to determine session mode, transport, and checkout experience at orchestration time."
5 +---
6 +
7 +The Wallet Confidence Score (WCS) is ProcureNet's buyer identity scoring engine. Every time a session is created, the WCS engine evaluates the signals you supply — such as a customer ID, email address, phone number, or device fingerprint — assigns weighted point values to each, and produces a numeric score. That score determines which orchestration mode the session enters and which real-time transport protocol is used to deliver events. The higher the score, the more ProcureNet knows about the buyer, and the more streamlined the checkout experience becomes.
8 +
9 +## Scoring Signals
10 +
11 +Each signal you pass in the `hints` object of `POST /api/v7/orchestrate` contributes a fixed number of points toward the total WCS. Signals are additive — providing more signals always raises the score.
12 +
13 +<ParamField body="customerId" type="string">
14 + **100 points** — The strongest possible signal. A recognized customer ID confirms a returning buyer with a known purchase history. Supplying this alone is enough to enter resolved mode.
15 +</ParamField>
16 +
17 +<ParamField body="email" type="string">
18 + **40 points** — A verified email address. Combined with a customer ID, this raises the score to 140 and reinforces identity confidence.
19 +</ParamField>
20 +
21 +<ParamField body="phone" type="string">
22 + **40 points** — A verified phone number. Carries the same weight as email and can substitute for it when email is unavailable.
23 +</ParamField>
24 +
25 +<ParamField body="deviceId" type="string">
26 + **20 points** — A device fingerprint or persistent device identifier. Useful for recognizing repeat sessions from the same hardware even without account credentials.
27 +</ParamField>
28 +
29 +The maximum possible score is **200 points**, achieved by supplying all four signals.
30 +
31 +## Score Thresholds and Routing
32 +
33 +ProcureNet maps WCS ranges to orchestration modes and transport protocols. The assignment happens at session creation and is immutable for the lifetime of that session.
34 +
35 +| Score Range | Mode | Transport | Prefill Available |
36 +|---|---|---|---|
37 +| ≥ 100 | `resolved` | Server-Sent Events (SSE) | Yes |
38 +| 40 – 99 | `partial` | WebSocket | No |
39 +| < 40 | `anonymous` | WebSocket | No |
40 +
41 +See [Orchestration Modes](/concepts/orchestration-modes) for a full breakdown of what each mode enables.
42 +
43 +## TypeScript Example
44 +
45 +The `WCSEngine.calculate()` method is called automatically during orchestration, but you can also invoke it directly in your integration code to predict routing before making the API call.
46 +
47 +```typescript
48 +import { WCSEngine } from './scoring/WCSEngine';
49 +
50 +const result = WCSEngine.calculate({
51 + customerId: 'cust_123',
52 + email: 'user@example.com',
53 + phone: null,
54 + deviceId: 'dev_456',
55 +});
56 +
57 +// result.score → 160
58 +// result.mode → 'resolved'
59 +// result.transport → 'sse'
60 +```
61 +
62 +In this example, `customerId` contributes 100 pts, `email` adds 40 pts, and `deviceId` adds 20 pts, producing a total of 160 — well above the resolved threshold.
63 +
64 +<Note>
65 + You never need to call `WCSEngine.calculate()` yourself in production. ProcureNet computes the WCS automatically when you call `POST /api/v7/orchestrate`. Pass your buyer signals in the `hints` object of the request body, and the response will include `wcs_score`, `mode`, and `transport`.
66 +</Note>
67 +
68 +<Tip>
69 + Supplying a `customerId` alone guarantees resolved mode. At 100 points, it clears the threshold on its own — no additional signals required.
70 +</Tip>
configuration/ai-agents.mdx new
+99
@@ -0,0 +1,99 @@
1 +---
2 +title: "OpenClaw AI Agent Swarm Configuration Guide"
3 +sidebarTitle: "AI Agents"
4 +description: "Learn how ProcureNet's OpenClaw worker fleet handles security, reliability, and observability automatically — and what that means for your integration."
5 +---
6 +
7 +ProcureNet's OpenClaw agent swarm runs a fleet of specialized AI workers that handle security, data reliability, observability, and procurement automation. These agents operate continuously in the background on your behalf — you do not invoke them directly or manage their lifecycle. Instead, you configure their behavior through settings in your integration and interpret the signals they surface, such as trace IDs and webhook retry outcomes.
8 +
9 +## Key Worker Classes
10 +
11 +OpenClaw currently runs 10+ worker classes. The three below have the most direct impact on your day-to-day integration.
12 +
13 +<CardGroup cols={3}>
14 + <Card title="claw-v1 — Security" icon="shield-halved">
15 + Verifies every inbound webhook signature using HMAC validation. When
16 + `claw-v1` rejects a delivery, ProcureNet returns a `401` before your
17 + application code ever sees the payload — protecting you from forged
18 + callbacks.
19 + </Card>
20 + <Card title="claw-v3 — Reliability" icon="database">
21 + Manages session state persistence to durable storage. If your server
22 + restarts mid-session, `claw-v3` ensures the session is recoverable and
23 + state transitions can resume exactly where they left off.
24 + </Card>
25 + <Card title="claw-v10 — Diagnostics" icon="magnifying-glass-chart">
26 + Emits structured logs and attaches a traceable ID to every session event
27 + and payment flow. You surface this ID via the `x-trace-id` response header
28 + to correlate incidents when contacting support.
29 + </Card>
30 +</CardGroup>
31 +
32 +---
33 +
34 +## How Agents Affect Your Integration
35 +
36 +<Steps>
37 + <Step title="Webhook delivery retries are automatic">
38 + If ProcureNet cannot reach your webhook endpoint, the agent swarm queues
39 + the delivery for retry using exponential back-off. You do not need to
40 + implement your own retry logic for missed callbacks — just ensure your
41 + endpoint is idempotent by checking the `payment_id` or `session_id`
42 + before processing duplicate deliveries.
43 + </Step>
44 + <Step title="Sessions survive server restarts">
45 + Because `claw-v3` persists state externally, a session that was in-flight
46 + when your server went down is still valid when it comes back up. Resume it
47 + by calling `POST /api/v7/sessions/{id}/transition` with the same session ID
48 + — the state machine picks up from its last confirmed position.
49 + </Step>
50 + <Step title="Payment failures are traceable">
51 + When a USDC payment confirmation fails, `claw-v10` records the failure with
52 + a unique trace ID attached to the `x-trace-id` header on the originating
53 + API response. Log that header value and include it in any support ticket —
54 + it lets the ProcureNet team locate the exact event in the diagnostics
55 + pipeline without requiring you to reproduce the failure.
56 + </Step>
57 +</Steps>
58 +
59 +---
60 +
61 +## Frequently Asked Questions
62 +
63 +<Accordion title="Can I configure which agents run?">
64 + No. The OpenClaw agent swarm is fully managed by ProcureNet and runs
65 + automatically for every account. There is no option to enable or disable
66 + individual workers. All 10+ worker classes are active on your sessions from
67 + the moment you create them.
68 +</Accordion>
69 +
70 +<Accordion title="How do I know if an agent is failing?">
71 + Check the `x-trace-id` response header on API calls. Every response from a
72 + ProcureNet session or payment endpoint includes this header. If you observe
73 + unexpected behavior — stale state, missed webhook deliveries, unconfirmed
74 + payments — record the trace ID from the relevant response and include it when
75 + you contact ProcureNet support. The diagnostics team can use it to pinpoint
76 + exactly which worker encountered an error and when.
77 +</Accordion>
78 +
79 +<Accordion title="Are agent skills updated automatically?">
80 + Yes. ProcureNet deploys agent skill updates as part of regular platform
81 + releases. New capabilities are added to the 48-skill manifest without
82 + changing any public API contract, so your integration does not need to be
83 + modified when updates ship. You will see improvements in accuracy and
84 + coverage automatically.
85 +</Accordion>
86 +
87 +<Accordion title="What happens if an agent is temporarily unavailable?">
88 + ProcureNet is designed for agent-level fault tolerance. If a single worker
89 + is unavailable, in-flight sessions remain intact because `claw-v3` has
90 + already persisted their state. Webhook retries continue to queue. You may
91 + notice slightly elevated latency on affected operations, which resolves once
92 + the worker recovers. No manual intervention is required on your side.
93 +</Accordion>
94 +
95 +---
96 +
97 +<Note>
98 + OpenClaw currently runs 10+ worker classes with a 48-skill manifest planned. New skills are deployed transparently — your integration code does not need to change to benefit from expanded agent capabilities as they roll out.
99 +</Note>
configuration/environment.mdx new
+128
@@ -0,0 +1,128 @@
1 +---
2 +title: "Configure ProcureNet for Your Environment"
3 +sidebarTitle: "Environment"
4 +description: "Set up your API credentials, choose an EVM payment network, and tune the VCI bridge — everything you need to connect your app to ProcureNet."
5 +---
6 +
7 +ProcureNet exposes a set of configuration options you control through your account settings and API keys. This page covers the **customer-configurable** settings only — what you pass in API calls and set in your application. You will not need to touch any infrastructure; every option described here is a value you supply at initialization time or as an HTTP header.
8 +
9 +## API Credentials
10 +
11 +ProcureNet uses four distinct credentials, each scoped to a specific surface. Keep them in separate environment variables and never commit them to source control.
12 +
13 +<CardGroup cols={2}>
14 + <Card title="Wallet API Key" icon="key">
15 + Passed as the `x-perplexity-mod-key` header on all wallet and payment
16 + endpoints. Obtain this from the **API Keys** section of your ProcureNet
17 + dashboard.
18 + </Card>
19 + <Card title="JWT Bearer Token" icon="lock">
20 + Passed as `Authorization: Bearer <token>` on session endpoints. Generated
21 + when you authenticate your account via ProcureNet's auth flow.
22 + </Card>
23 + <Card title="Webhook Secret" icon="webhook">
24 + Used to verify the `x-procure-signature` HMAC on inbound Procurement
25 + Express callbacks. Copy it from the **Webhooks** tab in your dashboard.
26 + </Card>
27 + <Card title="Admin Key" icon="shield">
28 + Passed as `x-admin-key` when triggering manual payment confirmation.
29 + Keep this completely separate from your regular API key and restrict
30 + its use to server-side code only.
31 + </Card>
32 +</CardGroup>
33 +
34 +<Tip>
35 + Store all four credentials as environment variables (e.g., `PROCURENET_API_KEY`, `PROCURENET_JWT`, `PROCURENET_WEBHOOK_SECRET`, `PROCURENET_ADMIN_KEY`). Reference them at runtime — never hard-code credential strings in your source files.
36 +</Tip>
37 +
38 +<Warning>
39 + The admin key (`x-admin-key`) carries elevated privileges that can override payment confirmation. Restrict it to server-side processes only and rotate it immediately if it is ever exposed.
40 +</Warning>
41 +
42 +---
43 +
44 +## Payment Networks
45 +
46 +Every USDC payment request targets a specific EVM network. You choose the network per request by passing the `network` field in your payment payload.
47 +
48 +| Network | When to use |
49 +| ----------- | -------------------------------------------------------- |
50 +| `base` | Recommended default — lowest transaction fees |
51 +| `arbitrum` | Low fees with broad DeFi ecosystem support |
52 +| `polygon` | Established network with wide wallet compatibility |
53 +| `ethereum` | Maximum compatibility when recipients require mainnet |
54 +
55 +<Info>
56 + Use `base` for the majority of field evaluator payouts to minimize on-chain costs. Switch to `ethereum` only when a recipient's wallet does not support Layer 2 networks.
57 +</Info>
58 +
59 +---
60 +
61 +## VCI Bridge Configuration
62 +
63 +The `VCIProcureNetBridge` connects your offline VCI evaluation queue to ProcureNet's USDC wallet. You configure its behavior through two options passed to `ProcureNetWalletClient`.
64 +
65 +<ParamField body="autoWatch" type="boolean" default="true">
66 + When `true`, the bridge automatically polls for on-chain confirmation after
67 + creating a payment request — no extra calls needed from your side. Set to
68 + `false` if you want to control the confirmation check yourself by calling
69 + `manualConfirmPayment()` explicitly.
70 +</ParamField>
71 +
72 +<ParamField body="tenantIdResolver" type="() => string" default="() => 'default-tenant'">
73 + A function you provide that returns your tenant ID string. The bridge calls
74 + this resolver each time it creates a payment, so you can return a dynamic
75 + value (e.g., from your session context) if you operate multiple tenants.
76 +</ParamField>
77 +
78 +### Initialization example
79 +
80 +Pass your base URL and API key to `ProcureNetWalletClient`, then hand the client to `VCIProcureNetBridge` alongside your queue adapter and tenant resolver.
81 +
82 +<CodeGroup>
83 +
84 +```typescript TypeScript
85 +import {
86 + ProcureNetWalletClient,
87 + VCIProcureNetBridge,
88 +} from '@procurenet/vci-bridge';
89 +
90 +const wallet = new ProcureNetWalletClient(
91 + 'https://api.procurenet.io', // base URL
92 + process.env.PROCURENET_API_KEY!, // x-perplexity-mod-key
93 + { autoWatch: true } // watch for on-chain confirmation automatically
94 +);
95 +
96 +const bridge = new VCIProcureNetBridge(
97 + myQueueAdapter, // your QueueLike implementation
98 + wallet,
99 + () => process.env.TENANT_ID! // tenantIdResolver
100 +);
101 +```
102 +
103 +```typescript Manual confirmation (autoWatch: false)
104 +import {
105 + ProcureNetWalletClient,
106 + VCIProcureNetBridge,
107 +} from '@procurenet/vci-bridge';
108 +
109 +const wallet = new ProcureNetWalletClient(
110 + 'https://api.procurenet.io',
111 + process.env.PROCURENET_API_KEY!,
112 + { autoWatch: false } // you will call manualConfirmPayment() yourself
113 +);
114 +
115 +const bridge = new VCIProcureNetBridge(myQueueAdapter, wallet);
116 +
117 +// Later, after the evaluator submits offline data:
118 +const result = await bridge.manualConfirmPayment(
119 + localEvaluationId,
120 + process.env.PROCURENET_ADMIN_KEY!
121 +);
122 +
123 +if (result.confirmed) {
124 + console.log('Payment confirmed on-chain:', result.transaction_hash);
125 +}
126 +```
127 +
128 +</CodeGroup>
configuration/vector-store.mdx new
+135
@@ -0,0 +1,135 @@
1 +---
2 +title: "ProcureNet Local-First Vector Store Configuration"
3 +sidebarTitle: "Vector Store"
4 +description: "Understand how ProcureNet's four vector indexes — wcs_profiles, contract_rules, translations, and entitlements — drive AI lookups in your checkout flows."
5 +---
6 +
7 +ProcureNet uses a local-first vector store to power AI-driven lookups for buyer profiles, contract rules, translations, and entitlements. The store runs on-device alongside the OpenClaw agent swarm, meaning reads are low-latency and survive network interruptions. You do not write vectors yourself — the platform populates and queries the store automatically based on the data you supply to the orchestration API.
8 +
9 +## The Four Indexes
10 +
11 +The vector store contains four named indexes. Each serves a distinct role in the orchestration pipeline.
12 +
13 +<CardGroup cols={2}>
14 + <Card title="wcs_profiles" icon="user">
15 + **Type: `scoring`**
16 +
17 + Stores embedding representations of buyer identity signals. Powers the Wallet Confidence Score engine to resolve sessions as `resolved`, `partial`, or `anonymous`.
18 + </Card>
19 + <Card title="contract_rules" icon="file-contract">
20 + **Type: `validation`**
21 +
22 + Holds procurement contract terms and validation logic. Checked during state transitions to ensure orders comply with applicable rules before advancing.
23 + </Card>
24 + <Card title="translations" icon="language">
25 + **Type: `i18n`**
26 +
27 + Contains localized string embeddings for checkout UI flows. Enables ProcureNet to serve the correct language and locale to buyers without round-trips to a remote translation service.
28 + </Card>
29 + <Card title="entitlements" icon="badge-check">
30 + **Type: `authorization`**
31 +
32 + Controls which features and funding methods a buyer or account can access. Queried when you call the funding-method endpoint to verify the buyer is permitted to use the selected payment method.
33 + </Card>
34 +</CardGroup>
35 +
36 +---
37 +
38 +## Vector Item Structure
39 +
40 +Every item stored in any index shares the same shape, defined in ProcureNet's internal schema.
41 +
42 +<ResponseField name="id" type="string" required>
43 + A unique identifier for this vector item within its index.
44 +</ResponseField>
45 +
46 +<ResponseField name="vector" type="number[]" required>
47 + The embedding float array produced by the index's configured embedding model.
48 + Array length matches the `dimensions` value declared for that index.
49 +</ResponseField>
50 +
51 +<ResponseField name="payload" type="object" required>
52 + Arbitrary metadata attached to the vector item. Shape varies by index type —
53 + for example, `wcs_profiles` payloads contain buyer signal fields, while
54 + `contract_rules` payloads contain rule predicates.
55 +</ResponseField>
56 +
57 +<ResponseField name="updatedAt" type="string (ISO 8601)" required>
58 + Timestamp of the last write to this item. Used by the OpenClaw reliability
59 + worker to detect stale entries and trigger re-embedding.
60 +</ResponseField>
61 +
62 +<ResponseField name="ttlSeconds" type="integer">
63 + Optional expiry in seconds from `updatedAt`. When set, the item is
64 + automatically evicted from the index once the TTL elapses. Commonly applied
65 + to `wcs_profiles` items for short-lived anonymous sessions.
66 +</ResponseField>
67 +
68 +---
69 +
70 +## How Each Index Affects Your Integration
71 +
72 +The indexes work together as a pipeline. Understanding their roles helps you pass the right data at the right time.
73 +
74 +<Steps>
75 + <Step title="Buyer signals flow into wcs_profiles">
76 + When you call `POST /api/v7/orchestrate`, ProcureNet embeds the identity
77 + signals you supply in the `hints` object — `customerId`, `email`, `phone`,
78 + and `deviceId` — and queries the `wcs_profiles` index to calculate the
79 + Wallet Confidence Score. A richer profile means a higher score and a
80 + `resolved` session mode.
81 + </Step>
82 + <Step title="contract_rules validates state transitions">
83 + Before the state machine advances on `POST /api/v7/sessions/{id}/transition`,
84 + applicable rules from `contract_rules` are retrieved and evaluated. If your
85 + order violates a procurement rule, the transition is rejected with a
86 + validation error.
87 + </Step>
88 + <Step title="translations localise the checkout flow">
89 + ProcureNet resolves the buyer's locale from session context and queries the
90 + `translations` index to return correctly localised strings. No action is
91 + required from you — locale handling is automatic.
92 + </Step>
93 + <Step title="entitlements gate funding methods">
94 + When you call `POST /api/v7/sessions/{id}/funding-method`, ProcureNet
95 + queries the `entitlements` index against the buyer's session to confirm
96 + the requested payment method is permitted. Requests for unauthorised
97 + methods are rejected with a `403` response.
98 + </Step>
99 +</Steps>
100 +
101 +---
102 +
103 +## Schema Reference (Condensed)
104 +
105 +The full index schema follows JSON Schema draft 2020-12. The abbreviated structure below shows the shape of each index object.
106 +
107 +```json JSON
108 +{
109 + "indexes": {
110 + "<index_name>": {
111 + "name": "string",
112 + "type": "i18n | validation | scoring | authorization",
113 + "embeddingModel": "string",
114 + "dimensions": 1536,
115 + "items": [
116 + {
117 + "id": "string",
118 + "vector": [0.021, -0.113, "..."],
119 + "payload": {},
120 + "updatedAt": "2025-01-15T10:30:00Z",
121 + "ttlSeconds": 3600
122 + }
123 + ]
124 + }
125 + }
126 +}
127 +```
128 +
129 +<Note>
130 + The vector store is managed internally by OpenClaw agents — you do not write vectors directly. Buyer data you pass to `POST /api/v7/orchestrate` is used to populate and query profiles automatically.
131 +</Note>
132 +
133 +<Tip>
134 + If buyer lookups are returning `anonymous` mode unexpectedly, ensure you are passing all four identity signals — `customerId`, `email`, `phone`, and `deviceId` — in the `hints` object of your orchestration request. Missing signals reduce the Wallet Confidence Score and may drop the session below the `resolved` threshold of 100 points.
135 +</Tip>
docs.json
+75 -58
@@ -1,72 +1,89 @@
1 {
2 "$schema": "https://mintlify.com/docs.json",
3 - "theme": "mint",
4 - "name": "Mintlify Starter Kit",
3 + "name": "ProcureNet",
4 + "theme": "luma",
5 "colors": {
6 - "primary": "#16A34A",
7 - "light": "#07C983",
8 - "dark": "#15803D"
6 + "primary": "#6C47FF",
7 + "light": "#EDE9FF",
8 + "dark": "#3B1FA8"
9 },
10 "favicon": "/favicon.svg",
11 "navigation": {
12 - "pages": [
12 + "tabs": [
13 {
14 - "group": "Getting Started",
15 - "pages": [
16 - "index",
17 - "quickstart"
14 + "tab": "Documentation",
15 + "groups": [
16 + {
17 + "group": "Get Started",
18 + "pages": [
19 + "introduction",
20 + "quickstart",
21 + "authentication"
22 + ]
23 + },
24 + {
25 + "group": "Core Concepts",
26 + "pages": [
27 + "concepts/wallet-confidence-score",
28 + "concepts/session-lifecycle",
29 + "concepts/orchestration-modes",
30 + "concepts/payment-settlement"
31 + ]
32 + },
33 + {
34 + "group": "Guides",
35 + "pages": [
36 + "guides/integrate-checkout",
37 + "guides/field-evaluation-payments",
38 + "guides/webhooks",
39 + "guides/escrow-flows"
40 + ]
41 + },
42 + {
43 + "group": "Configuration",
44 + "pages": [
45 + "configuration/environment",
46 + "configuration/vector-store",
47 + "configuration/ai-agents"
48 + ]
49 + }
50 ]
19 - }
20 - ],
21 - "global": {
22 - "anchors": [
23 - {
24 - "anchor": "Documentation",
25 - "href": "https://mintlify.com/docs",
26 - "icon": "book-open-cover"
27 - },
28 - {
29 - "anchor": "Blog",
30 - "href": "https://mintlify.com/blog",
31 - "icon": "newspaper"
32 - }
33 - ]
34 - }
35 - },
36 - "logo": {
37 - "light": "/logo/light.svg",
38 - "dark": "/logo/dark.svg"
39 - },
40 - "navbar": {
41 - "links": [
51 + },
52 {
43 - "label": "Support",
44 - "href": "mailto:hi@mintlify.com"
53 + "tab": "API Reference",
54 + "groups": [
55 + {
56 + "group": "Orchestration",
57 + "pages": [
58 + "api/orchestrate",
59 + "api/sessions-prefill",
60 + "api/sessions-transition",
61 + "api/sessions-escrow-accept",
62 + "api/sessions-funding-method"
63 + ]
64 + },
65 + {
66 + "group": "Payments",
67 + "pages": [
68 + "api/usdc-request",
69 + "api/usdc-watch",
70 + "api/usdc-manual-confirm"
71 + ]
72 + },
73 + {
74 + "group": "Webhooks",
75 + "pages": [
76 + "api/webhook-procurement"
77 + ]
78 + }
79 + ]
80 }
46 - ],
47 - "primary": {
48 - "type": "button",
49 - "label": "Dashboard",
50 - "href": "https://app.mintlify.com"
51 - }
52 - },
53 - "contextual": {
54 - "options": [
55 - "copy",
56 - "view",
57 - "chatgpt",
58 - "claude",
59 - "perplexity",
60 - "mcp",
61 - "cursor",
62 - "vscode"
81 ]
82 },
65 - "footer": {
66 - "socials": {
67 - "x": "https://x.com/mintlify",
68 - "github": "https://github.com/mintlify",
69 - "linkedin": "https://linkedin.com/company/mintlify"
83 + "navbar": {
84 + "primary": {
85 + "type": "github",
86 + "href": "https://github.com/mindtdilly"
87 }
88 }
72 -}
\ No newline at end of file
89 +}
guides/escrow-flows.mdx new
+88
@@ -0,0 +1,88 @@
1 +---
2 +title: "Use Escrow Flows for High-Value Transactions"
3 +sidebarTitle: "Escrow Flows"
4 +description: "Trigger and accept ProcureNet escrow on high-value sessions to satisfy compliance requirements and generate an immutable procurement audit trail."
5 +---
6 +
7 +For high-value procurement transactions, ProcureNet automatically routes sessions through an escrow acceptance step before funds are committed. This provides a legally meaningful checkpoint — an authorized party explicitly accepts the transaction terms — and writes an immutable audit trail entry that cannot be altered or deleted after acceptance. If your account has a transaction threshold configured, any session that crosses it will pause at `escrow_pending` and wait for an authorized call to proceed.
8 +
9 +## When Escrow Is Triggered
10 +
11 +ProcureNet transitions a session to the `escrow_pending` state automatically when the transaction amount exceeds your account's configured threshold. You do not need to request this manually. Once a session enters `escrow_pending`, it will not advance until an authorized party calls the escrow acceptance endpoint.
12 +
13 +<Info>
14 + Your transaction threshold is defined by your account policy. To review or adjust your threshold, contact ProcureNet support.
15 +</Info>
16 +
17 +## How the Escrow Flow Works
18 +
19 +<Steps>
20 +
21 +### Session Reaches `escrow_pending`
22 +
23 +When the session amount exceeds your threshold, ProcureNet pauses the session and emits an `escrow_pending` state event on your session stream. Listen for this state on your SSE or WebSocket connection to trigger any UI-level review prompt.
24 +
25 +### Authorized Party Reviews Transaction Details
26 +
27 +Before calling the escrow acceptance endpoint, the authorized buyer or delegated party should review the transaction amount, funding method, and any procurement contract terms associated with the session. This review step is your compliance window.
28 +
29 +### Call `POST /api/v7/sessions/{id}/escrow-accept`
30 +
31 +Send a `POST` request to the escrow acceptance endpoint with a valid Bearer JWT. The JWT must belong to the authorized buyer or a delegated party with escrow acceptance permissions.
32 +
33 +```typescript
34 +const res = await fetch(
35 + `https://api.procurenet.io/api/v7/sessions/${sessionId}/escrow-accept`,
36 + {
37 + method: 'POST',
38 + headers: {
39 + 'Authorization': `Bearer ${jwtToken}`,
40 + 'Content-Type': 'application/json'
41 + }
42 + }
43 +);
44 +
45 +if (res.ok) {
46 + console.log('Escrow accepted, session advancing to funded state');
47 +}
48 +```
49 +
50 +### ProcureNet Writes the Audit Trail Entry
51 +
52 +Immediately upon acceptance, ProcureNet records an immutable audit trail entry capturing the session ID, accepting party identity, timestamp, and transaction details. This entry is written before the session advances and cannot be modified or deleted.
53 +
54 +### Session Advances to `funded`
55 +
56 +After the audit trail is written, ProcureNet transitions the session to the `funded` state and resumes the orchestration flow. Your session stream will emit the new state.
57 +
58 +</Steps>
59 +
60 +## Authorization Requirements
61 +
62 +<Note>
63 + Only the authorized buyer or a delegated party holding a valid JWT with escrow acceptance permissions can call `POST /api/v7/sessions/{id}/escrow-accept`. Calls with an unauthorized or expired JWT return `403 Forbidden`.
64 +</Note>
65 +
66 +Ensure your JWT is issued with the correct claims before calling this endpoint. If you are delegating escrow acceptance to a procurement agent or system account, verify that the delegated JWT has the `escrow:accept` scope.
67 +
68 +<Warning>
69 + Escrow acceptance is irreversible. Once you call the endpoint, the audit trail entry is written and the session advances. There is no undo operation — if you need to stop the transaction after acceptance, you must raise a support ticket for manual escalation.
70 +</Warning>
71 +
72 +## Frequently Asked Questions
73 +
74 +<Accordion title="What counts as a high-value transaction?">
75 + The threshold is defined by your account's transaction threshold policy and is set during account configuration. ProcureNet compares the session's `amount` field against this threshold to determine whether to enter the `escrow_pending` state. Contact ProcureNet support to review or request a change to your account's threshold.
76 +</Accordion>
77 +
78 +<Accordion title="Can I cancel after escrow is accepted?">
79 + No. Once escrow is accepted, the session must proceed to completion. The audit trail entry is immutable and the session state cannot be rolled back programmatically. If you need to halt the transaction after acceptance, contact ProcureNet support to raise a manual escalation ticket — the support team can intervene before funds are fully committed.
80 +</Accordion>
81 +
82 +<Accordion title="What happens if the escrow-accept call fails?">
83 + If the endpoint returns a non-2xx response, the session remains in `escrow_pending` and no audit trail entry is written. Retry the call after resolving the issue (for example, refreshing an expired JWT). The session will not time out of `escrow_pending` automatically unless your account has an inactivity policy configured.
84 +</Accordion>
85 +
86 +<Accordion title="Can I automate escrow acceptance?">
87 + Yes. You can call `POST /api/v7/sessions/{id}/escrow-accept` from a server-side service as long as the request includes a valid JWT with the appropriate permissions. Ensure your automated system includes adequate review logic before accepting — the acceptance is irreversible.
88 +</Accordion>
guides/field-evaluation-payments.mdx new
+123
@@ -0,0 +1,123 @@
1 +---
2 +title: "Automate Field Evaluator Payments with VCI Bridge"
3 +sidebarTitle: "Field Payments"
4 +description: "Automatically pay field evaluators in USDC when their offline assessments sync — no manual intervention required for eligible score tiers."
5 +---
6 +
7 +ProcureNet's VCI bridge connects your offline field evaluation queue directly to the USDC payment infrastructure. When a field evaluator completes assessments without connectivity and later comes back online, the bridge intercepts the sync event, calculates the appropriate USDC payout based on the evaluator's average score, creates a payment request, and fires a wallet event your UI can listen to. You handle the UI feedback; ProcureNet handles the on-chain settlement.
8 +
9 +## How the Payment Flow Works
10 +
11 +<Steps>
12 +
13 +### Evaluator Completes Assessments Offline
14 +
15 +Field evaluators submit assessments through your app while disconnected. These records are queued locally on the device until connectivity is restored.
16 +
17 +### Evaluation Queue Syncs on Reconnect
18 +
19 +When the device comes back online, the evaluation queue syncs and fires a `vci-sync-status` browser event. This is the trigger that kicks off the automated payment flow.
20 +
21 +### VCIProcureNetBridge Calculates the Payout
22 +
23 +The bridge intercepts `vci-sync-status`, reads the evaluator's average score across all synced assessments, and maps that score to a USDC payout tier.
24 +
25 +| Avg Evaluation Score | USDC Payout |
26 +|---|---|
27 +| ≥ 9.0 | 500 USDC |
28 +| ≥ 7.0 | 250 USDC |
29 +| ≥ 5.0 | 100 USDC |
30 +| < 5.0 | 0 USDC (no payment) |
31 +
32 +### Payment Request Is Created and Attached
33 +
34 +The bridge calls `POST /mods/procurement_wallet/usdc/request` to create a USDC payment request on the configured network. The response includes a `deposit_address` and an optional `qr_code`. Both are attached to the evaluation record for traceability.
35 +
36 +GPS metadata captured by the field device — latitude, longitude, accuracy, and timestamp — is automatically included in the payment request metadata, creating a location-stamped audit record.
37 +
38 +### `vci-wallet-sync` Event Fires
39 +
40 +Once the payment request is created, the bridge dispatches a `vci-wallet-sync` browser event containing the payment details. Your UI can listen for this event to show confirmation feedback to the evaluator.
41 +
42 +### ProcureNet Watches for On-Chain Confirmation
43 +
44 +If you instantiate the bridge with `autoWatch: true`, ProcureNet polls `GET /mods/procurement_wallet/usdc/watch/{paymentId}` automatically and resolves the payment once the transaction is confirmed on-chain. If `autoWatch` is false, you trigger confirmation manually.
45 +
46 +</Steps>
47 +
48 +## Setting Up the Bridge
49 +
50 +Instantiate `ProcureNetWalletClient` with your API key and bridge configuration, then pass it to `VCIProcureNetBridge` along with your evaluation queue and a tenant resolver function.
51 +
52 +```typescript
53 +import { VCIProcureNetBridge, ProcureNetWalletClient } from './integrations/VCIProcureNetBridge';
54 +
55 +const wallet = new ProcureNetWalletClient(
56 + 'https://api.procurenet.io',
57 + process.env.PROCURENET_API_KEY!,
58 + { autoWatch: true }
59 +);
60 +
61 +const bridge = new VCIProcureNetBridge(queue, wallet, () => 'tenant_abc');
62 +```
63 +
64 +<Note>
65 + The `x-perplexity-mod-key` header is set automatically from the API key you pass to `ProcureNetWalletClient`. You do not need to attach it manually to wallet endpoint calls.
66 +</Note>
67 +
68 +## Supported Networks
69 +
70 +ProcureNet's USDC bridge supports the following networks. Specify the target network when configuring your wallet client:
71 +
72 +<CardGroup cols={2}>
73 + <Card title="Base" icon="circle-b">
74 + Low-fee L2 — recommended for high-volume field payment operations.
75 + </Card>
76 + <Card title="Arbitrum" icon="circle-a">
77 + High-throughput L2 with strong DeFi ecosystem support.
78 + </Card>
79 + <Card title="Polygon" icon="hexagon">
80 + Fast finality and broad wallet compatibility for field devices.
81 + </Card>
82 + <Card title="Ethereum" icon="ethereum">
83 + Mainnet settlement for maximum finality guarantees on high-value payments.
84 + </Card>
85 +</CardGroup>
86 +
87 +## Listening for Payment Events
88 +
89 +Register a `vci-wallet-sync` listener in your frontend to surface payment confirmation details to the evaluator as soon as the payment request is created.
90 +
91 +```typescript
92 +window.addEventListener('vci-wallet-sync', (event) => {
93 + const { paymentId, amount, qrCode, expiresAt } = (event as CustomEvent).detail;
94 + console.log(`Payment ${paymentId} created for ${amount} USDC`);
95 + // Render qrCode and expiresAt in your UI for the evaluator to track
96 +});
97 +```
98 +
99 +## Manual Confirmation
100 +
101 +If you instantiate the bridge with `autoWatch: false`, you are responsible for triggering on-chain confirmation. Call `manualConfirmPayment` with the local evaluation record ID and your admin key.
102 +
103 +```typescript
104 +const result = await bridge.manualConfirmPayment(localId, adminKey);
105 +
106 +if (result.confirmed) {
107 + console.log('Transaction hash:', result.transaction_hash);
108 +}
109 +```
110 +
111 +<Tip>
112 + Use `autoWatch: true` for production deployments unless you have a specific reason to gate confirmation — it eliminates the need for a manual confirmation step and reduces payment latency.
113 +</Tip>
114 +
115 +## GPS Metadata Attachment
116 +
117 +<Info>
118 + Location metadata is attached automatically. If the field device has GPS enabled, the bridge reads `lat`, `lng`, `accuracy`, and `timestamp` from the device context and includes them in the payment request metadata sent to ProcureNet. No additional configuration is required.
119 +</Info>
120 +
121 +<Warning>
122 + Evaluations with an average score below 5.0 receive no USDC payment. Verify your scoring rubrics and calibration against this threshold before deploying the bridge to production — evaluators below the floor will not receive a payout regardless of submission volume.
123 +</Warning>
guides/integrate-checkout.mdx new
+183
@@ -0,0 +1,183 @@
1 +---
2 +title: "Integrate ProcureNet Checkout into Your App"
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.
40 +</Tip>
41 +
42 +### Start the Orchestration Session
43 +
44 +Call `POST /api/v7/orchestrate` with your buyer hints and transaction details. 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 + 'Authorization': `Bearer ${token}`
52 + },
53 + body: JSON.stringify({
54 + amount: 250.00,
55 + currency: 'USD',
56 + hints: {
57 + customerId: 'cust_123',
58 + email: 'buyer@example.com'
59 + }
60 + })
61 +});
62 +
63 +const { session_id, wcs_score, mode, transport } = await res.json();
64 +```
65 +
66 +Store `session_id` — every subsequent API call in this checkout flow requires it.
67 +
68 +### Connect to the Session Stream
69 +
70 +Use the `transport` value from the previous response to open the appropriate real-time connection to your session.
71 +
72 +<Tabs>
73 + <Tab title="SSE (resolved mode)">
74 + Use SSE when `transport` is `"sse"`. This is the most reliable transport for fully-identified buyers.
75 +
76 + ```typescript
77 + const eventSource = new EventSource(
78 + `https://api.procurenet.io/api/v7/sessions/${session_id}/stream`,
79 + { withCredentials: true }
80 + );
81 +
82 + eventSource.onmessage = (event) => {
83 + const data = JSON.parse(event.data);
84 + console.log('Session state:', data.state);
85 + };
86 + ```
87 + </Tab>
88 + <Tab title="WebSocket (partial / anonymous)">
89 + Use WebSocket when `transport` is `"websocket"`. This handles partial and anonymous sessions.
90 +
91 + ```typescript
92 + const ws = new WebSocket(
93 + `wss://api.procurenet.io/api/v7/sessions/${session_id}/stream`
94 + );
95 +
96 + ws.onmessage = (event) => {
97 + const data = JSON.parse(event.data);
98 + console.log('Session state:', data.state);
99 + };
100 + ```
101 + </Tab>
102 +</Tabs>
103 +
104 +### Handle Prefill for Resolved Sessions
105 +
106 +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 is only available for resolved sessions.
107 +
108 +```typescript
109 +const prefillRes = await fetch(
110 + `https://api.procurenet.io/api/v7/sessions/${session_id}/prefill`,
111 + {
112 + headers: {
113 + 'Authorization': `Bearer ${token}`
114 + }
115 + }
116 +);
117 +
118 +const prefillData = await prefillRes.json();
119 +// prefillData contains address, payment method hints, and buyer profile fields
120 +```
121 +
122 +<Note>
123 + Calling `/prefill` on a `partial` or `anonymous` session returns a `403`. Always guard this call with a `mode === 'resolved'` check.
124 +</Note>
125 +
126 +### Set the Funding Method
127 +
128 +Once the buyer has selected a payment method, register it against the session by calling `POST /api/v7/sessions/{id}/funding-method`.
129 +
130 +```typescript
131 +const fundingRes = await fetch(
132 + `https://api.procurenet.io/api/v7/sessions/${session_id}/funding-method`,
133 + {
134 + method: 'POST',
135 + headers: {
136 + 'Content-Type': 'application/json',
137 + 'Authorization': `Bearer ${token}`
138 + },
139 + body: JSON.stringify({
140 + type: 'card',
141 + token: 'pm_tok_visa_4242'
142 + })
143 + }
144 +);
145 +```
146 +
147 +### Advance Through Session States
148 +
149 +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.
150 +
151 +```typescript
152 +const transitionRes = await fetch(
153 + `https://api.procurenet.io/api/v7/sessions/${session_id}/transition`,
154 + {
155 + method: 'POST',
156 + headers: {
157 + 'Content-Type': 'application/json',
158 + 'Authorization': `Bearer ${token}`
159 + },
160 + body: JSON.stringify({ event: 'confirm' })
161 + }
162 +);
163 +
164 +const { state } = await transitionRes.json();
165 +console.log('New session state:', state);
166 +```
167 +
168 +Listen on your stream connection for real-time state change events alongside explicit transition calls.
169 +
170 +</Steps>
171 +
172 +## Migrating from the Legacy Payments Route
173 +
174 +<Warning>
175 + `POST /api/payments/route` is deprecated and will be removed in a future release. Migrate to `POST /api/v7/orchestrate` as soon as possible.
176 +</Warning>
177 +
178 +The legacy `POST /api/payments/route` endpoint does not support WCS scoring, session streaming, or prefill. To migrate:
179 +
180 +1. Replace calls to `/api/payments/route` with `POST /api/v7/orchestrate`.
181 +2. Update your response handling to read `session_id`, `wcs_score`, `mode`, and `transport` from the new response shape.
182 +3. Connect to the session stream using the transport returned in step 2.
183 +4. Use `/funding-method` and `/transition` to replace any inline payment routing logic you had in the old flow.
guides/webhooks.mdx new
+139
@@ -0,0 +1,139 @@
1 +---
2 +title: "Receive Procurement Approval Webhooks Securely"
3 +sidebarTitle: "Webhooks"
4 +description: "Verify HMAC-signed Procurement Express callbacks and use approval decisions to resume or terminate your orchestration sessions in real time."
5 +---
6 +
7 +When a procurement approval decision is made in Procurement Express, ProcureNet sends a signed HTTP callback to your registered endpoint. These webhooks let your backend react to approval outcomes in real time — resuming a suspended orchestration flow on approval or cleaning up session state on rejection. Every inbound callback includes an `x-procure-signature` HMAC header that you must verify before processing any payload.
8 +
9 +## Webhook Payload
10 +
11 +Every callback sent to `POST /webhooks/procurement` contains the following fields:
12 +
13 +<ResponseField name="session_id" type="string" required>
14 + The ProcureNet session ID this decision applies to.
15 +</ResponseField>
16 +
17 +<ResponseField name="decision" type="string" required>
18 + The approval outcome. One of `"approved"` or `"rejected"`.
19 +</ResponseField>
20 +
21 +<ResponseField name="actor" type="string" required>
22 + The identifier of the user or system that made the approval decision.
23 +</ResponseField>
24 +
25 +<ResponseField name="reason" type="string">
26 + An optional human-readable explanation for the decision. Populated on rejections and some approvals.
27 +</ResponseField>
28 +
29 +## Setting Up Your Webhook Endpoint
30 +
31 +<Steps>
32 +
33 +### Obtain Your Webhook Secret
34 +
35 +Log in to ProcureNet settings and navigate to **Webhooks**. Generate or copy your webhook secret. Store it as an environment variable — never hard-code it in source.
36 +
37 +```bash
38 +export WEBHOOK_SECRET=your_webhook_secret_here
39 +```
40 +
41 +### Register Your Endpoint URL
42 +
43 +In ProcureNet settings, add your server's public URL as a Procurement Express callback target. ProcureNet will `POST` to this URL for every approval decision event.
44 +
45 +### Implement HMAC Verification
46 +
47 +For every inbound request, compute the expected HMAC signature from the raw request body using your webhook secret and compare it to the `x-procure-signature` header. Reject any request where they do not match.
48 +
49 +```typescript
50 +import { createHmac } from 'crypto';
51 +
52 +function verifySignature(payload: string, signature: string, secret: string): boolean {
53 + const expected = createHmac('sha256', secret).update(payload).digest('hex');
54 + return `sha256=${expected}` === signature;
55 +}
56 +
57 +// In your webhook handler:
58 +app.post('/webhooks/procurement', (req, res) => {
59 + const signature = req.headers['x-procure-signature'] as string;
60 + const rawBody = JSON.stringify(req.body);
61 +
62 + if (!verifySignature(rawBody, signature, process.env.WEBHOOK_SECRET!)) {
63 + return res.status(401).send('Invalid signature');
64 + }
65 +
66 + const { session_id, decision, actor } = req.body;
67 + // Resume or cancel the orchestration flow based on the decision
68 + res.status(204).send();
69 +});
70 +```
71 +
72 +<Warning>
73 + Always verify the `x-procure-signature` header before reading or acting on the payload. Never trust unverified callbacks — an attacker could spoof approval decisions against your endpoint.
74 +</Warning>
75 +
76 +### Return HTTP 204 on Success
77 +
78 +Respond with `204 No Content` after successfully processing the webhook. ProcureNet treats any non-2xx response as a failure and will retry delivery with exponential backoff.
79 +
80 +</Steps>
81 +
82 +## Handling Decisions in Your Application
83 +
84 +<Note>
85 + An `"approved"` decision resumes a suspended orchestration flow — call `POST /api/v7/sessions/{id}/transition` with the appropriate event to continue. A `"rejected"` decision terminates the session; clean up any pending UI state and notify the buyer.
86 +</Note>
87 +
88 +Use the `decision` field to branch your handler logic:
89 +
90 +```typescript
91 +app.post('/webhooks/procurement', (req, res) => {
92 + const signature = req.headers['x-procure-signature'] as string;
93 + const rawBody = JSON.stringify(req.body);
94 +
95 + if (!verifySignature(rawBody, signature, process.env.WEBHOOK_SECRET!)) {
96 + return res.status(401).send('Invalid signature');
97 + }
98 +
99 + const { session_id, decision, actor, reason } = req.body;
100 +
101 + if (decision === 'approved') {
102 + // Resume the orchestration session
103 + resumeSession(session_id);
104 + } else if (decision === 'rejected') {
105 + // Terminate session and surface the reason to the buyer
106 + cancelSession(session_id, reason);
107 + }
108 +
109 + res.status(204).send();
110 +});
111 +```
112 +
113 +## Signature Verification Reference
114 +
115 +The `x-procure-signature` header uses the format `sha256=<hex_digest>`. ProcureNet computes the HMAC-SHA256 of the raw JSON request body using your webhook secret. Your verification must use the **raw body bytes** — do not parse and re-serialize the JSON before computing the digest, as field ordering or whitespace differences will cause a mismatch.
116 +
117 +<CodeGroup>
118 +
119 +```typescript TypeScript
120 +import { createHmac } from 'crypto';
121 +
122 +function verifySignature(payload: string, signature: string, secret: string): boolean {
123 + const expected = createHmac('sha256', secret).update(payload).digest('hex');
124 + return `sha256=${expected}` === signature;
125 +}
126 +```
127 +
128 +```python Python
129 +import hmac
130 +import hashlib
131 +
132 +def verify_signature(payload: str, signature: str, secret: str) -> bool:
133 + expected = 'sha256=' + hmac.new(
134 + secret.encode(), payload.encode(), hashlib.sha256
135 + ).hexdigest()
136 + return hmac.compare_digest(expected, signature)
137 +```
138 +
139 +</CodeGroup>
index.mdx
+59 -15
@@ -1,20 +1,64 @@
1 ---
2 -title: "Introduction"
3 -description: "Welcome to your project"
2 +title: "ProcureNet: AI-Powered Procurement Orchestration"
3 +sidebarTitle: "Home"
4 +description: "ProcureNet orchestrates checkout and procurement flows using AI, routing buyers intelligently via Wallet Confidence Score and settling payments in USDC on-chain."
5 ---
6
6 -Write a short description of your product here. What it does, who it's for, and what they can accomplish with it.
7 +ProcureNet is an AI-powered procurement orchestration platform that intelligently routes buyer sessions, automates checkout flows, and settles field evaluation payments using USDC stablecoins on EVM networks. Whether you're embedding a smart checkout experience or automating field worker compensation, ProcureNet gives you a single, unified API to manage the full procurement lifecycle.
8
8 -<Tip>
9 - Ready to make this your own? Start by editing this page. Update your `docs.json` file to customize your site. Then fill out the [Quickstart](/quickstart) page.
10 -</Tip>
9 +<CardGroup cols={2}>
10 + <Card title="Quick Start" icon="rocket" href="/quickstart">
11 + Make your first orchestration call and route a buyer session in minutes.
12 + </Card>
13 + <Card title="Authentication" icon="key" href="/authentication">
14 + Learn how to obtain and use API keys and JWT Bearer tokens.
15 + </Card>
16 + <Card title="API Reference" icon="code" href="/api/orchestrate">
17 + Explore every endpoint — orchestration, sessions, payments, and webhooks.
18 + </Card>
19 + <Card title="Core Concepts" icon="lightbulb" href="/concepts/wallet-confidence-score">
20 + Understand Wallet Confidence Score, session modes, and payment settlement.
21 + </Card>
22 +</CardGroup>
23
12 -<Card title="Quickstart" icon="rocket" href="/quickstart">
13 - This card links to the quickstart page in your project.
14 -</Card>
15 -<Card title="Components" icon="puzzle-piece" href="https://mintlify.com/docs/components">
16 - Add cards, callouts, steps, tabs, and more to design and structure your pages.
17 -</Card>
18 -<Card title="Settings" icon="gear" href="https://mintlify.com/docs/organize/settings">
19 - Set your site name, branding, and navigation in the `docs.json` file.
20 -</Card>
24 +## How ProcureNet Works
25 +
26 +ProcureNet evaluates each buyer session using its **Wallet Confidence Score (WCS)** engine — a weighted signal that scores what is known about the buyer and routes them through the optimal checkout flow automatically.
27 +
28 +<Steps>
29 + <Step title="Start an orchestration session">
30 + Send buyer signals (customer ID, email, phone, device ID) to `POST /api/v7/orchestrate`. ProcureNet calculates a WCS and returns a `session_id`, score, mode, and transport type.
31 + </Step>
32 + <Step title="Connect via SSE or WebSocket">
33 + Resolved sessions (WCS ≥ 100) stream updates over **Server-Sent Events**. Partial and anonymous sessions use **WebSocket** for real-time interaction during the checkout flow.
34 + </Step>
35 + <Step title="Advance the session state machine">
36 + Call `POST /api/v7/sessions/{id}/transition` to move the session through procurement states. Set a funding method, accept escrow for high-value transactions, or retrieve prefill data for known buyers.
37 + </Step>
38 + <Step title="Settle payments on-chain">
39 + Once field evaluations sync or procurement is approved, ProcureNet automatically creates USDC payment requests and watches for on-chain confirmation — no manual reconciliation needed.
40 + </Step>
41 +</Steps>
42 +
43 +## Key Features
44 +
45 +<CardGroup cols={2}>
46 + <Card title="Wallet Confidence Score" icon="chart-bar" href="/concepts/wallet-confidence-score">
47 + Dynamic buyer scoring routes sessions to resolved, partial, or anonymous checkout modes.
48 + </Card>
49 + <Card title="USDC Settlement" icon="coins" href="/concepts/payment-settlement">
50 + Automated stablecoin payments on Base, Arbitrum, Polygon, and Ethereum.
51 + </Card>
52 + <Card title="Field Evaluation Payments" icon="map-pin" href="/guides/field-evaluation-payments">
53 + Pay field evaluators automatically when offline work syncs, with GPS metadata attached.
54 + </Card>
55 + <Card title="Procurement Webhooks" icon="webhook" href="/guides/webhooks">
56 + Receive signed approval callbacks from Procurement Express with HMAC verification.
57 + </Card>
58 + <Card title="Escrow Flows" icon="shield-check" href="/guides/escrow-flows">
59 + Immutable audit trails and legal compliance for high-value transactions.
60 + </Card>
61 + <Card title="OpenClaw AI Agents" icon="robot" href="/configuration/ai-agents">
62 + A 10+ worker AI agent swarm that automates procurement intelligence tasks.
63 + </Card>
64 +</CardGroup>
introduction.mdx new
+58
@@ -0,0 +1,58 @@
1 +---
2 +title: "ProcureNet: AI-Powered Procurement Orchestration Platform"
3 +sidebarTitle: "Introduction"
4 +description: "ProcureNet orchestrates checkout sessions with real-time buyer scoring, AI agent automation, and on-chain USDC payments for field evaluators."
5 +---
6 +
7 +ProcureNet is an AI-powered procurement and checkout orchestration platform that brings together real-time buyer identity scoring, stateful session management, on-chain payment settlement, and a swarm of intelligent procurement agents — all through a unified API. Whether you're embedding a checkout flow into your storefront, automating supplier procurement, or paying field evaluators for completed work, ProcureNet gives you a single surface to coordinate the entire journey.
8 +
9 +<CardGroup cols={2}>
10 + <Card title="Quickstart" icon="bolt" href="/quickstart">
11 + Make your first orchestration call and connect to a live session stream in minutes.
12 + </Card>
13 + <Card title="Authentication" icon="lock" href="/authentication">
14 + Learn how API keys, JWT tokens, webhook signatures, and admin keys work together.
15 + </Card>
16 + <Card title="Core Concepts" icon="layer-group" href="/concepts">
17 + Understand WCS scoring, session state machines, and transport selection.
18 + </Card>
19 + <Card title="API Reference" icon="code" href="/api/orchestrate">
20 + Full reference for every v7 endpoint, request schema, and response shape.
21 + </Card>
22 +</CardGroup>
23 +
24 +## What ProcureNet Does
25 +
26 +ProcureNet handles four distinct areas of procurement orchestration:
27 +
28 +**Wallet Confidence Score (WCS) Engine** — Every session begins with a WCS calculation. You pass identity hints (customer ID, email, phone, device ID) when you start a session, and the engine scores the buyer's resolvability from 0 to 200. That score determines the session mode and the real-time transport ProcureNet assigns.
29 +
30 +**Stateful Session API (v7)** — Sessions progress through a well-defined state machine. You start orchestration, retrieve prefill data for known buyers, set a funding method, accept escrow for high-value transactions, and advance the state via explicit transition calls. Every state change is observable.
31 +
32 +**USDC Payment Bridge** — Field evaluators who complete offline evaluations receive on-chain USDC payments when their work syncs. The bridge calculates payout tier from average evaluation scores and settles directly to a deposit address on your chosen network (Base, Arbitrum, Polygon, or Ethereum).
33 +
34 +**OpenClaw AI Agent Swarm** — A swarm of 10+ AI workers runs procurement intelligence tasks in the background: sourcing suppliers, validating contract rules, resolving entitlements, and enriching session context from the local-first vector store.
35 +
36 +## Session Modes
37 +
38 +The WCS score your session receives determines which mode — and which real-time transport — ProcureNet assigns. Understanding these modes helps you build the right client-side connection logic.
39 +
40 +<CardGroup cols={3}>
41 + <Card title="Resolved" icon="circle-check">
42 + **Score ≥ 100** — The buyer's identity is fully established (typically a known customer ID plus at least one contact signal). ProcureNet assigns SSE transport and enables prefill data retrieval so you can pre-populate checkout fields automatically.
43 + </Card>
44 + <Card title="Partial" icon="circle-half-stroke">
45 + **Score 40–99** — The buyer is partially identified, for example by email or phone but without a matched customer ID. ProcureNet assigns WebSocket transport. Prefill is not available, but the session remains stateful and can be upgraded if identity resolves later.
46 + </Card>
47 + <Card title="Anonymous" icon="circle-xmark">
48 + **Score &lt; 40** — No strong identity signals are present. ProcureNet assigns WebSocket transport. The session is still fully orchestrated, but buyer-specific features like prefill and escrow auto-accept are unavailable until identity is established.
49 + </Card>
50 +</CardGroup>
51 +
52 +<Note>
53 + Your session mode is determined at the moment you call `POST /api/v7/orchestrate`. If your buyer's identity context changes mid-session (for example, they log in), start a new orchestration call with updated hints to re-score and potentially upgrade to a higher mode.
54 +</Note>
55 +
56 +## The Local-First Vector Store
57 +
58 +ProcureNet's OpenClaw swarm operates against a local-first vector store that holds four index types: **WCS profiles** for scoring history, **contract rules** for procurement validation, **translations** for i18n content, and **entitlements** for authorization. This store runs on-device, keeping latency low and allowing the swarm to operate even during intermittent connectivity — crucial for field evaluation workflows.
quickstart.mdx
+193 -27
@@ -1,47 +1,213 @@
1 ---
2 -title: "Quickstart"
3 -description: "Begin with a guide on the fastest path to a successful outcome"
2 +title: "Get Started with ProcureNet Orchestration API Fast"
3 +sidebarTitle: "Quickstart"
4 +description: "Start a WCS-scored procurement session, connect to the real-time stream, and advance your first state machine transition in under 10 minutes."
5 ---
6
6 -Describe how someone begins using your product. What is the first thing they need to do? Are there any prerequisites?
7 +This guide walks you through the fastest path to a working ProcureNet integration. You'll obtain your API key, start a scored orchestration session, connect to the session's real-time stream, and fire your first state transition — all with TypeScript examples you can run directly against the API. By the end, you'll have a live session flowing through ProcureNet's v7 orchestration pipeline.
8
8 -A quickstart should take someone from zero to using your product. They'll get a quick win and a sense of what they can accomplish.
9 +<Steps>
10
10 -## Prerequisites
11 + <Step title="Obtain your API key">
12 + ProcureNet uses separate credentials for different parts of the API. For session orchestration you need a **JWT token** (covered in [Authentication](/authentication)), but to call wallet and payment endpoints you'll need a **mod key**.
13
12 -Before you begin, you must have:
14 + Request your API key from the ProcureNet dashboard or your account team. Once issued, you'll use it as the `x-perplexity-mod-key` header on all wallet and payment requests.
15
14 -- Requirement one (for example, Node.js 18+, a free account, an API key)
15 -- Requirement two (for example, a compatible device, a compatible browser, a compatible operating system)
16 + Store your key in an environment variable and never hard-code it in client-side code:
17
17 -## Get started
18 + ```typescript
19 + // .env
20 + PROCURENET_MOD_KEY=your_mod_key_here
21 + PROCURENET_JWT=your_jwt_token_here
22 + PROCURENET_BASE_URL=https://api.procurenet.io
23 + ```
24
19 -<Steps>
20 - <Step title="Install">
21 - Describe how to install your product or sign up.
25 + <Warning>
26 + Never expose your `x-perplexity-mod-key` or JWT in browser-side JavaScript or public repositories. These credentials carry full API access for their respective scopes.
27 + </Warning>
28 + </Step>
29 +
30 + <Step title="Start an orchestration session">
31 + Call `POST /api/v7/orchestrate` to create a session. Pass identity hints for the buyer — the more signals you provide, the higher the Wallet Confidence Score (WCS) and the richer the session capabilities you'll unlock.
32
23 - ```bash
24 - npm install your-package
33 + The `hints` object accepts any combination of `customerId`, `email`, `phone`, and `deviceId`. Each contributes to the WCS score:
34 + - `customerId` — 100 points
35 + - `email` — 40 points
36 + - `phone` — 40 points
37 + - `deviceId` — 20 points (max total: 200)
38 +
39 + ```typescript
40 + const response = await fetch(
41 + `${process.env.PROCURENET_BASE_URL}/api/v7/orchestrate`,
42 + {
43 + method: "POST",
44 + headers: {
45 + "Content-Type": "application/json",
46 + Authorization: `Bearer ${process.env.PROCURENET_JWT}`,
47 + },
48 + body: JSON.stringify({
49 + amount: 1250.00,
50 + currency: "USD",
51 + hints: {
52 + customerId: "cust_01HXYZ9ABC",
53 + email: "buyer@example.com",
54 + phone: "+14155552671",
55 + deviceId: "dev_fingerprint_abc123",
56 + },
57 + }),
58 + }
59 + );
60 +
61 + const session = await response.json();
62 + console.log(session);
63 ```
26 - </Step>
27 - <Step title="Configure">
28 - Describe any setup or configuration needed before first use.
64
30 - ```bash
31 - your-cli init
65 + A successful response returns the session identifier, the calculated WCS score, the resolved mode, and the transport type to use for your real-time connection:
66 +
67 + ```json
68 + {
69 + "session_id": "sess_01JKAB3MXPQ7RVTZWN5",
70 + "wcs_score": 200,
71 + "mode": "resolved",
72 + "transport": "sse"
73 + }
74 ```
75 +
76 + Use the `mode` and `transport` fields together to decide how to connect in the next step.
77 +
78 + <Tip>
79 + A `wcs_score` of 200 means all four identity hints were present and valid. A score ≥ 100 puts the session in `resolved` mode and unlocks prefill data retrieval via `GET /api/v7/sessions/{id}/prefill`.
80 + </Tip>
81 + </Step>
82 +
83 + <Step title="Connect to the session stream">
84 + ProcureNet pushes real-time session events over either SSE or WebSocket depending on the `transport` value in your orchestration response. Open the appropriate connection immediately after starting the session.
85 +
86 + <Tabs>
87 + <Tab title="SSE (resolved sessions)">
88 + Use SSE when `transport` is `"sse"` — this applies to all sessions with a WCS score ≥ 100.
89 +
90 + ```typescript
91 + // Connect to SSE stream for resolved sessions
92 + const sessionId = session.session_id;
93 + const streamUrl = `${process.env.PROCURENET_BASE_URL}/api/v7/sessions/${sessionId}/stream`;
94 +
95 + const eventSource = new EventSource(streamUrl, {
96 + // Pass auth via query param or use a server-side proxy
97 + // that adds the Authorization header
98 + withCredentials: true,
99 + });
100 +
101 + eventSource.onmessage = (event) => {
102 + const data = JSON.parse(event.data);
103 + console.log("Session event:", data);
104 + };
105 +
106 + eventSource.onerror = (error) => {
107 + console.error("SSE connection error:", error);
108 + eventSource.close();
109 + };
110 + ```
111 + </Tab>
112 + <Tab title="WebSocket (partial / anonymous sessions)">
113 + Use WebSocket when `transport` is `"websocket"` — this applies to sessions with a WCS score below 100.
114 +
115 + ```typescript
116 + // Connect to WebSocket stream for partial or anonymous sessions
117 + const sessionId = session.session_id;
118 + const wsUrl = `wss://api.procurenet.io/api/v7/sessions/${sessionId}/ws`;
119 +
120 + const ws = new WebSocket(wsUrl);
121 +
122 + ws.onopen = () => {
123 + // Authenticate the WebSocket connection on open
124 + ws.send(
125 + JSON.stringify({
126 + type: "auth",
127 + token: process.env.PROCURENET_JWT,
128 + })
129 + );
130 + };
131 +
132 + ws.onmessage = (event) => {
133 + const data = JSON.parse(event.data);
134 + console.log("Session event:", data);
135 + };
136 +
137 + ws.onerror = (error) => {
138 + console.error("WebSocket error:", error);
139 + };
140 + ```
141 + </Tab>
142 + </Tabs>
143 +
144 + <Info>
145 + Keep your stream connection open for the lifetime of the session. ProcureNet emits state transition events, escrow status updates, and swarm intelligence results over this channel in real time.
146 + </Info>
147 </Step>
34 - <Step title="Run it">
35 - Show the first thing a user does to see it working.
148
37 - ```bash
38 - your-cli start
149 + <Step title="Advance the session state">
150 + Sessions move through a state machine. Call `POST /api/v7/sessions/{id}/transition` with the target state to advance the session. ProcureNet validates the transition against the current state and rejects illegal moves with a deterministic error code.
151 +
152 + ```typescript
153 + const sessionId = session.session_id;
154 +
155 + const transitionResponse = await fetch(
156 + `${process.env.PROCURENET_BASE_URL}/api/v7/sessions/${sessionId}/transition`,
157 + {
158 + method: "POST",
159 + headers: {
160 + "Content-Type": "application/json",
161 + Authorization: `Bearer ${process.env.PROCURENET_JWT}`,
162 + },
163 + body: JSON.stringify({
164 + target_state: "awaiting_payment",
165 + }),
166 + }
167 + );
168 +
169 + if (!transitionResponse.ok) {
170 + const error = await transitionResponse.json();
171 + console.error("Transition rejected:", error);
172 + } else {
173 + const result = await transitionResponse.json();
174 + console.log("New session state:", result.state);
175 + }
176 ```
177 +
178 + After a successful transition, ProcureNet emits a transition event on your stream connection. Your stream handler receives the new state so your UI can update without polling.
179 +
180 + <Tip>
181 + For high-value transactions, call `POST /api/v7/sessions/{id}/escrow-accept` before the final transition to satisfy ProcureNet's legal compliance requirement. The escrow endpoint writes an immutable audit trail entry that unlocks the payment transition.
182 + </Tip>
183 </Step>
184 +
185 </Steps>
186
43 -<Tip>
44 - Give people a way to get help. This could be a link to a support page, a chat with a customer support agent, or a forum for your product.
187 +## Deprecated Endpoint Notice
188 +
189 +<Warning>
190 + **`POST /api/payments/route` is deprecated** and will be removed in a future release. Migrate to the v7 pipeline:
191 +
192 + 1. Call `POST /api/v7/orchestrate` to start a WCS-scored session.
193 + 2. Call `POST /api/v7/sessions/{id}/funding-method` to set the payment method on the session.
194 +
195 + The old `/api/payments/route` endpoint does not support WCS scoring, transport selection, or the v7 state machine. Any new integration should use the v7 endpoints exclusively.
196 +</Warning>
197 +
198 +## Next Steps
199
46 - Example: Need help? Reach out to us at [support@yourcompany.com](mailto:support@yourcompany.com).
47 -</Tip>
200 +<CardGroup cols={2}>
201 + <Card title="Authentication" icon="lock" href="/authentication">
202 + Understand all four credential types and when to use each one.
203 + </Card>
204 + <Card title="Prefill Data" icon="fill" href="/api/sessions-prefill">
205 + Retrieve pre-populated buyer fields for resolved sessions (WCS ≥ 100).
206 + </Card>
207 + <Card title="USDC Payments" icon="circle-dollar-to-slot" href="/guides/field-evaluation-payments">
208 + Pay field evaluators on-chain when offline evaluations sync.
209 + </Card>
210 + <Card title="Webhooks" icon="webhook" href="/guides/webhooks">
211 + Handle Procurement Express callbacks with HMAC signature verification.
212 + </Card>
213 +</CardGroup>