Skip to content

Commit 860af2f

Browse files
committed
refactor: update secure payment page integration doc description
1 parent ac74c2b commit 860af2f

2 files changed

Lines changed: 260 additions & 0 deletions

File tree

Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
---
2+
title: "Secure Payment Integration Guide"
3+
description: "Integrate a secure payment experience via a secured link (redirect)"
4+
---
5+
6+
## Overview
7+
8+
This guide shows how to integrate Secure Payment Pages in a production-ready way.
9+
10+
The recommended pattern is:
11+
1. Create secure payment links with `POST /v2/secure-payments`
12+
2. Store returned `requestIds` in your system
13+
3. Redirect the payer to the secure page
14+
4. Use webhooks as the source of truth for payment status updates
15+
16+
## Prerequisites
17+
18+
Before you integrate, make sure you have:
19+
20+
- An API key or a Client ID linked to your integration domain
21+
- A webhook endpoint configured in Request Portal
22+
- Your webhook signing secret stored securely on your backend
23+
24+
For setup details, see:
25+
- [Authentication](/api-reference/authentication)
26+
- [Webhooks](/api-reference/webhooks)
27+
28+
## Quick start
29+
30+
<Steps>
31+
<Step title="Create secure payment links">
32+
Call `POST /v2/secure-payments` and store the returned `requestIds`.
33+
34+
<RequestExample>
35+
```bash cURL
36+
curl -X POST "https://api.request.network/v2/secure-payments" \
37+
-H "x-api-key: YOUR_API_KEY" \
38+
-H "Content-Type: application/json" \
39+
-d '{
40+
"requests": [
41+
{
42+
"payee": "0x6923831ACf5c327260D7ac7C9DfF5b1c3cB3C7D7",
43+
"amount": "10",
44+
"invoiceCurrency": "USDC-base",
45+
"paymentCurrency": "USDC-base"
46+
}
47+
]
48+
}'
49+
```
50+
</RequestExample>
51+
52+
<ResponseExample>
53+
```json 201 Created
54+
{
55+
"requestIds": [
56+
"01e273ecc29d4b526df3a0f1f05ffc59372af8752c2b678096e49ac270416a7cdb"
57+
],
58+
"securePaymentUrl": "https://secure.request.network/?token=01ABC123DEF456GHI789JKL",
59+
"token": "01ABC123DEF456GHI789JKL"
60+
}
61+
```
62+
</ResponseExample>
63+
</Step>
64+
65+
<Step title="Persist payment mapping in your database">
66+
Store at least:
67+
- your internal metadata
68+
- returned `requestIds`
69+
- `token`
70+
- `securePaymentUrl`
71+
72+
This mapping lets you reconcile webhook events back to your internal records.
73+
</Step>
74+
75+
<Step title="Redirect payer to secure page">
76+
Redirect in the same tab or open the secure URL in a new tab.
77+
</Step>
78+
79+
<Step title="Process webhook events and update order status">
80+
Handle payment events from webhooks and update your order/payment state from those events.
81+
</Step>
82+
</Steps>
83+
84+
## Integration pattern: generated URL + redirect
85+
86+
### Backend example (Node.js/Express)
87+
88+
```javascript server.js
89+
import express from "express";
90+
91+
const app = express();
92+
app.use(express.json());
93+
94+
app.post("/api/checkout/secure-payment", async (req, res) => {
95+
const { orderId, payee, amount, currencyId } = req.body;
96+
97+
const apiResponse = await fetch("https://api.request.network/v2/secure-payments", {
98+
method: "POST",
99+
headers: {
100+
"x-api-key": process.env.REQUEST_API_KEY,
101+
"content-type": "application/json",
102+
},
103+
body: JSON.stringify({
104+
requests: [
105+
{
106+
payee,
107+
amount,
108+
invoiceCurrency: currencyId,
109+
paymentCurrency: currencyId,
110+
},
111+
],
112+
}),
113+
});
114+
115+
if (!apiResponse.ok) {
116+
const errorBody = await apiResponse.text();
117+
return res.status(apiResponse.status).json({ error: errorBody });
118+
}
119+
120+
const securePayment = await apiResponse.json();
121+
122+
// Persist in your DB
123+
// Example payload:
124+
// {
125+
// orderId,
126+
// requestIds: securePayment.requestIds,
127+
// token: securePayment.token,
128+
// securePaymentUrl: securePayment.securePaymentUrl,
129+
// status: "pending"
130+
// }
131+
132+
return res.status(200).json({
133+
orderId,
134+
securePaymentUrl: securePayment.securePaymentUrl,
135+
});
136+
});
137+
```
138+
139+
### Frontend redirect examples
140+
141+
<CodeGroup>
142+
```javascript Same tab
143+
window.location.href = securePaymentUrl;
144+
```
145+
146+
```javascript New tab
147+
window.open(securePaymentUrl, "_blank", "noopener,noreferrer");
148+
```
149+
</CodeGroup>
150+
151+
## Payment status updates with webhooks
152+
153+
Use webhook events as your payment status source of truth.
154+
155+
Typical mapping:
156+
- `payment.confirmed` -> mark order as paid
157+
- `payment.partial` -> mark order as partially paid
158+
- `payment.failed` -> mark order as failed
159+
160+
### Webhook handler example (signature verification + reconciliation)
161+
162+
```javascript webhook.js
163+
import crypto from "node:crypto";
164+
import express from "express";
165+
166+
const app = express();
167+
168+
app.use(
169+
express.raw({
170+
type: "application/json",
171+
verify: (req, _res, buf) => {
172+
req.rawBody = buf;
173+
},
174+
}),
175+
);
176+
177+
app.post("/webhooks/request", async (req, res) => {
178+
const signature = req.headers["x-request-network-signature"];
179+
const secret = process.env.REQUEST_WEBHOOK_SECRET;
180+
181+
const expectedSignature = crypto
182+
.createHmac("sha256", secret)
183+
.update(req.rawBody)
184+
.digest("hex");
185+
186+
if (!signature) {
187+
return res.status(401).json({ error: "Missing signature" });
188+
}
189+
190+
try {
191+
const isValid = crypto.timingSafeEqual(
192+
Buffer.from(signature),
193+
Buffer.from(expectedSignature),
194+
);
195+
if (!isValid) {
196+
return res.status(401).json({ error: "Invalid signature" });
197+
}
198+
} catch {
199+
return res.status(401).json({ error: "Invalid signature format" });
200+
}
201+
202+
const event = JSON.parse(req.rawBody.toString("utf8"));
203+
const requestId = event.requestId || event.requestID;
204+
205+
// Find internal record by requestId in your DB, then update order status.
206+
// Example:
207+
// const checkout = await db.findCheckoutByRequestId(requestId)
208+
// if (event.event === "payment.confirmed") await db.markPaid(checkout.orderId)
209+
210+
return res.status(200).json({ received: true });
211+
});
212+
```
213+
214+
## Expiry handling
215+
216+
Secure payment links expire after one week by default.
217+
218+
If a payer opens an expired link, create a new secure payment link and redirect again.
219+
220+
## Troubleshooting
221+
222+
<AccordionGroup>
223+
<Accordion title="401 Unauthorized when creating secure payments">
224+
- Verify your `x-api-key` or `x-client-id` header
225+
- If using Client ID in browser, verify the request origin is in allowed domains
226+
</Accordion>
227+
228+
<Accordion title="403 when loading secure payment token">
229+
- The token may be expired
230+
- Create a fresh secure payment link and retry
231+
</Accordion>
232+
233+
<Accordion title="409 already completed">
234+
- Payment is already completed
235+
- Show a paid/completed state in your app instead of retrying payment
236+
</Accordion>
237+
238+
<Accordion title="Webhook events not updating order status">
239+
- Verify HMAC signature validation uses raw request body
240+
- Ensure your endpoint returns `2xx` after successful processing
241+
- Confirm your DB lookup maps incoming `requestId`/`requestID` to stored request IDs
242+
</Accordion>
243+
</AccordionGroup>
244+
245+
## Related docs
246+
247+
<CardGroup cols={3}>
248+
<Card title="Secure Payments API Reference" href="/api-reference/secure-payments" icon="book">
249+
Full request and response schema details.
250+
</Card>
251+
252+
<Card title="Webhooks" href="/api-reference/webhooks" icon="webhook">
253+
Event types, signing, retries, and payload details.
254+
</Card>
255+
256+
<Card title="Authentication" href="/api-reference/authentication" icon="key">
257+
API key and Client ID setup.
258+
</Card>
259+
</CardGroup>

docs.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@
105105
"group": "Secure Payment Pages",
106106
"pages": [
107107
"api-features/secure-payment-pages",
108+
"api-features/secure-payment-integration-guide",
108109
"api-features/secure-payment-supported-networks-and-currencies"
109110
]
110111
},

0 commit comments

Comments
 (0)