@siglume/direct-request-payment 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +50 -0
- package/README.md +271 -104
- package/dist/index.cjs +253 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +131 -1
- package/dist/index.d.ts +131 -1
- package/dist/index.js +253 -1
- package/dist/index.js.map +1 -1
- package/docs/announcement-ja.md +64 -0
- package/docs/api-reference.md +209 -51
- package/docs/merchant-quickstart.md +183 -142
- package/docs/pricing.md +36 -19
- package/docs/security.md +14 -0
- package/examples/express-checkout.ts +3 -2
- package/examples/setup-merchant.ts +17 -0
- package/package.json +15 -1
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.3.0 - 2026-06-12
|
|
4
|
+
|
|
5
|
+
Recurring payment approval release.
|
|
6
|
+
|
|
7
|
+
- Added recurring (subscription / scheduled autopay) merchant approval helpers
|
|
8
|
+
in TypeScript (`createDirectRequestPaymentRecurringChallenge`,
|
|
9
|
+
`createDirectRequestPaymentRecurringChallengeSignature`,
|
|
10
|
+
`verifyDirectRequestPaymentRecurringChallenge`) and Python
|
|
11
|
+
(`create_direct_request_payment_recurring_challenge`,
|
|
12
|
+
`create_direct_request_payment_recurring_challenge_signature`,
|
|
13
|
+
`verify_direct_request_payment_recurring_challenge`).
|
|
14
|
+
- Recurring approvals use a new single-use challenge scheme
|
|
15
|
+
(`siglume-external-402-recurring-v1`) with the cadence (`monthly` for
|
|
16
|
+
subscriptions, `daily` for scheduled autopay) bound into the HMAC, so
|
|
17
|
+
one-time checkout challenges and recurring approvals can never be replayed
|
|
18
|
+
as each other.
|
|
19
|
+
- Documented the recurring payment flow (subscription and scheduled autopay)
|
|
20
|
+
in the README.
|
|
21
|
+
- Updated pricing docs: the Launch plan's free monthly allowance of 100
|
|
22
|
+
payments is retired — Launch is now a flat 1.8% payment fee; the per-payment
|
|
23
|
+
minimum fee is JPY 30 (USD merchants: USD 0.20); JPY/JPYC and USD/USDC
|
|
24
|
+
settlement are both documented as first-class.
|
|
25
|
+
|
|
26
|
+
## 0.2.0 - 2026-06-12
|
|
27
|
+
|
|
28
|
+
Merchant self-service setup release.
|
|
29
|
+
|
|
30
|
+
- Added TypeScript `DirectRequestPaymentMerchantClient` and Python
|
|
31
|
+
`DirectRequestPaymentMerchantClient`.
|
|
32
|
+
- Added `setupCheckout` / `setup_checkout` to claim a merchant key, prepare a
|
|
33
|
+
billing mandate, and create a webhook subscription from the SDK.
|
|
34
|
+
- Added challenge secret rotation, merchant status lookup, billing mandate
|
|
35
|
+
preparation, and webhook subscription helpers.
|
|
36
|
+
- Updated docs to remove manual onboarding assumptions and clarify merchant JWT
|
|
37
|
+
vs buyer JWT responsibilities.
|
|
38
|
+
|
|
39
|
+
## 0.1.0 - 2026-06-11
|
|
40
|
+
|
|
41
|
+
Initial public release.
|
|
42
|
+
|
|
43
|
+
- Published TypeScript/JavaScript SDK as `@siglume/direct-request-payment`.
|
|
44
|
+
- Published Python SDK as `siglume-direct-request-payment`.
|
|
45
|
+
- Added merchant challenge helpers, buyer-authenticated Direct Request Payment
|
|
46
|
+
client methods, prepared transaction payload helpers, and webhook signature
|
|
47
|
+
verification helpers.
|
|
48
|
+
- Documented Launch, Starter, Growth, and Pro trial pricing.
|
|
49
|
+
- Documented the distinction from `@siglume/api-sdk` and Developer Portal
|
|
50
|
+
`cli_` API keys.
|
package/README.md
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# @siglume/direct-request-payment
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/@siglume/direct-request-payment)
|
|
4
|
+
[](https://pypi.org/project/siglume-direct-request-payment/)
|
|
5
|
+
|
|
3
6
|
Merchant SDK for Siglume Direct Request Payment checkout integrations.
|
|
4
7
|
|
|
5
8
|
Use this package when an external EC site, booking service, membership service,
|
|
@@ -12,18 +15,34 @@ This SDK is intentionally separate from `@siglume/api-sdk`:
|
|
|
12
15
|
- `@siglume/direct-request-payment` is for external merchants integrating
|
|
13
16
|
Siglume Direct Request Payment into their own checkout.
|
|
14
17
|
|
|
15
|
-
##
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
18
|
+
## What This SDK Covers
|
|
19
|
+
|
|
20
|
+
- merchant self-service setup with a Siglume merchant JWT
|
|
21
|
+
- challenge secret creation and rotation
|
|
22
|
+
- merchant billing mandate preparation
|
|
23
|
+
- webhook subscription creation
|
|
24
|
+
- merchant-signed payment challenges
|
|
25
|
+
- buyer-authenticated payment requirement creation
|
|
26
|
+
- prepared wallet transaction execution payloads
|
|
27
|
+
- payment requirement verification
|
|
28
|
+
- signed webhook verification
|
|
29
|
+
|
|
30
|
+
It does not custody funds or manage customer wallets. Merchant setup runs through
|
|
31
|
+
Siglume APIs with the merchant's Siglume JWT; buyer payment creation runs with
|
|
32
|
+
the buyer's Siglume JWT.
|
|
33
|
+
|
|
34
|
+
## Install
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npm install @siglume/direct-request-payment
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install siglume-direct-request-payment
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Node.js 18 or later is required for the TypeScript SDK. Python 3.11 or later is
|
|
45
|
+
required for the Python SDK.
|
|
27
46
|
|
|
28
47
|
## Current Platform Contract
|
|
29
48
|
|
|
@@ -36,8 +55,14 @@ context. Your merchant server must not use a merchant secret or API key to
|
|
|
36
55
|
charge a customer wallet. The merchant server creates the signed challenge; the
|
|
37
56
|
buyer-facing Siglume payment flow creates and pays the requirement.
|
|
38
57
|
|
|
39
|
-
`
|
|
40
|
-
|
|
58
|
+
`DirectRequestPaymentMerchantClient` requires the merchant's Siglume bearer
|
|
59
|
+
token for setup. `DirectRequestPaymentClient` requires the buyer's Siglume
|
|
60
|
+
bearer token for payment requirements. Do not use a Developer Portal `cli_` API
|
|
61
|
+
key with this package.
|
|
62
|
+
|
|
63
|
+
Current HTTP endpoints live under Siglume's market/API Store route namespace for
|
|
64
|
+
compatibility with the existing platform contract. That does not make this SDK an
|
|
65
|
+
API Store publishing SDK.
|
|
41
66
|
|
|
42
67
|
## Trial Pricing
|
|
43
68
|
|
|
@@ -45,28 +70,91 @@ Siglume Direct Request Payment is currently offered with trial-phase merchant
|
|
|
45
70
|
pricing designed for small EC sites, booking services, membership services, paid
|
|
46
71
|
APIs, and agent-to-agent payment experiments.
|
|
47
72
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
| Growth | JPY 2,980 | 0.7% |
|
|
53
|
-
| Pro | JPY 9,800 | 0.5% |
|
|
73
|
+
Both launch settlement currencies are first-class: JPY settled in JPYC, and USD
|
|
74
|
+
settled in USDC. A merchant settles in one currency, chosen at onboarding. The
|
|
75
|
+
settlement fee percentage is identical in both currencies; only the flat
|
|
76
|
+
amounts differ.
|
|
54
77
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
78
|
+
| Plan | Monthly fee (JPY / USD) | Payment fee |
|
|
79
|
+
| --- | ---: | ---: |
|
|
80
|
+
| Launch | JPY 0 / USD 0 | 1.8% |
|
|
81
|
+
| Starter | JPY 980 / USD 6.00 | 1.0% |
|
|
82
|
+
| Growth | JPY 2,980 / USD 18.00 | 0.7% |
|
|
83
|
+
| Pro | JPY 9,800 / USD 60.00 | 0.5% |
|
|
84
|
+
|
|
85
|
+
Every payment is fee-bearing at the plan rate. The minimum fee is JPY 30
|
|
86
|
+
(USD merchants: USD 0.20) per payment — it recovers the per-payment settlement
|
|
87
|
+
cost (an on-chain signature plus network gas) on small payments; the percentage
|
|
88
|
+
rate applies on larger payments. A merchant billing
|
|
89
|
+
mandate is required before accepting payments, even on the Launch plan. The API
|
|
90
|
+
and merchant registry may still expose the internal plan key `free` for this
|
|
91
|
+
tier. See [docs/pricing.md](./docs/pricing.md) for details.
|
|
60
92
|
|
|
61
93
|
Per-payment fees are deducted at payment settlement time, so the merchant
|
|
62
94
|
receives the net amount. Monthly base fees are collected through the merchant
|
|
63
|
-
billing mandate.
|
|
64
|
-
|
|
95
|
+
billing mandate. `fee_bps` returned on a payment requirement is the authoritative
|
|
96
|
+
per-payment rate for that payment in the merchant's settlement currency.
|
|
97
|
+
|
|
98
|
+
## Merchant Setup: One SDK Call
|
|
99
|
+
|
|
100
|
+
Run this once from the merchant server or an integration agent with the
|
|
101
|
+
merchant's Siglume JWT. It reserves the merchant key, creates the challenge
|
|
102
|
+
secret, prepares the billing mandate, and creates the webhook subscription.
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
import { DirectRequestPaymentMerchantClient } from "@siglume/direct-request-payment";
|
|
106
|
+
|
|
107
|
+
const merchant = new DirectRequestPaymentMerchantClient({
|
|
108
|
+
auth_token: process.env.SIGLUME_MERCHANT_AUTH_TOKEN!,
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
const setup = await merchant.setupCheckout({
|
|
112
|
+
merchant: "example_merchant",
|
|
113
|
+
display_name: "Example Merchant",
|
|
114
|
+
billing_plan: "launch",
|
|
115
|
+
billing_currency: "JPY",
|
|
116
|
+
webhook_callback_url: "https://merchant.example/siglume/webhook",
|
|
117
|
+
max_amount_minor: 100000,
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
console.log(setup.env);
|
|
121
|
+
// {
|
|
122
|
+
// SIGLUME_DIRECT_PAYMENT_MERCHANT: "example_merchant",
|
|
123
|
+
// SIGLUME_DIRECT_PAYMENT_CHALLENGE_SECRET: "edrp_...",
|
|
124
|
+
// SIGLUME_WEBHOOK_SECRET: "whsec_..."
|
|
125
|
+
// }
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
```py
|
|
129
|
+
import os
|
|
130
|
+
|
|
131
|
+
from siglume_direct_request_payment import DirectRequestPaymentMerchantClient
|
|
132
|
+
|
|
133
|
+
merchant = DirectRequestPaymentMerchantClient(
|
|
134
|
+
auth_token=os.environ["SIGLUME_MERCHANT_AUTH_TOKEN"],
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
setup = merchant.setup_checkout(
|
|
138
|
+
merchant="example_merchant",
|
|
139
|
+
display_name="Example Merchant",
|
|
140
|
+
billing_plan="launch",
|
|
141
|
+
billing_currency="JPY",
|
|
142
|
+
webhook_callback_url="https://merchant.example/siglume/webhook",
|
|
143
|
+
max_amount_minor=100000,
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
print(setup["env"])
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Store returned secrets on the merchant server. `challenge_secret` and
|
|
150
|
+
`signing_secret` are returned only when they are created or rotated. If a billing
|
|
151
|
+
mandate response requires wallet approval, complete that Siglume wallet step
|
|
152
|
+
before accepting production payments.
|
|
65
153
|
|
|
66
154
|
## Merchant Server: Create a Challenge
|
|
67
155
|
|
|
68
|
-
```ts
|
|
69
|
-
import { createDirectRequestPaymentChallenge } from "@siglume/direct-request-payment";
|
|
156
|
+
```ts
|
|
157
|
+
import { createDirectRequestPaymentChallenge } from "@siglume/direct-request-payment";
|
|
70
158
|
|
|
71
159
|
const challenge = await createDirectRequestPaymentChallenge({
|
|
72
160
|
merchant: "example_merchant",
|
|
@@ -78,26 +166,26 @@ const challenge = await createDirectRequestPaymentChallenge({
|
|
|
78
166
|
|
|
79
167
|
// Return only challenge.challenge to the buyer-facing checkout.
|
|
80
168
|
// Never return the challenge secret to the browser.
|
|
81
|
-
console.log(challenge.challenge);
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
```py
|
|
85
|
-
import os
|
|
86
|
-
|
|
87
|
-
from siglume_direct_request_payment import create_direct_request_payment_challenge
|
|
88
|
-
|
|
89
|
-
challenge = create_direct_request_payment_challenge(
|
|
90
|
-
merchant="example_merchant",
|
|
91
|
-
amount_minor=1200,
|
|
92
|
-
currency="JPY",
|
|
93
|
-
secret=os.environ["SIGLUME_DIRECT_PAYMENT_CHALLENGE_SECRET"],
|
|
94
|
-
nonce="order_123-attempt_1",
|
|
95
|
-
)
|
|
96
|
-
|
|
97
|
-
print(challenge["challenge"])
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
The signed challenge binds:
|
|
169
|
+
console.log(challenge.challenge);
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
```py
|
|
173
|
+
import os
|
|
174
|
+
|
|
175
|
+
from siglume_direct_request_payment import create_direct_request_payment_challenge
|
|
176
|
+
|
|
177
|
+
challenge = create_direct_request_payment_challenge(
|
|
178
|
+
merchant="example_merchant",
|
|
179
|
+
amount_minor=1200,
|
|
180
|
+
currency="JPY",
|
|
181
|
+
secret=os.environ["SIGLUME_DIRECT_PAYMENT_CHALLENGE_SECRET"],
|
|
182
|
+
nonce="order_123-attempt_1",
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
print(challenge["challenge"])
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
The signed challenge binds:
|
|
101
189
|
|
|
102
190
|
- merchant key
|
|
103
191
|
- amount in minor units
|
|
@@ -114,8 +202,8 @@ Use `DirectRequestPaymentClient` only with the authenticated buyer's Siglume
|
|
|
114
202
|
bearer token. `SIGLUME_AUTH_TOKEN` may be used in server-side payment-confirmation
|
|
115
203
|
helpers; `SIGLUME_API_KEY` and Developer Portal `cli_` keys are not accepted.
|
|
116
204
|
|
|
117
|
-
```ts
|
|
118
|
-
import { DirectRequestPaymentClient } from "@siglume/direct-request-payment";
|
|
205
|
+
```ts
|
|
206
|
+
import { DirectRequestPaymentClient } from "@siglume/direct-request-payment";
|
|
119
207
|
|
|
120
208
|
const siglume = new DirectRequestPaymentClient({
|
|
121
209
|
auth_token: buyerSiglumeBearerToken,
|
|
@@ -142,37 +230,103 @@ const verified = await siglume.verifyPaymentRequirement(requirement.requirement_
|
|
|
142
230
|
await_finality: false,
|
|
143
231
|
});
|
|
144
232
|
|
|
145
|
-
console.log(verified.status);
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
```py
|
|
149
|
-
from siglume_direct_request_payment import DirectRequestPaymentClient
|
|
150
|
-
|
|
151
|
-
siglume = DirectRequestPaymentClient(auth_token=buyer_siglume_bearer_token)
|
|
152
|
-
|
|
153
|
-
requirement = siglume.create_payment_requirement(
|
|
154
|
-
merchant="example_merchant",
|
|
155
|
-
amount_minor=1200,
|
|
156
|
-
currency="JPY",
|
|
157
|
-
challenge=challenge_from_merchant_server,
|
|
158
|
-
)
|
|
159
|
-
|
|
160
|
-
if requirement.get("approve_transaction_request"):
|
|
161
|
-
siglume.execute_allowance_transaction(requirement, await_finality=True)
|
|
162
|
-
|
|
163
|
-
payment = siglume.execute_payment_transaction(requirement, await_finality=True)
|
|
164
|
-
receipt_id = str((payment.get("receipt") or {}).get("receipt_id") or "")
|
|
165
|
-
|
|
166
|
-
verified = siglume.verify_payment_requirement(
|
|
167
|
-
requirement["requirement_id"],
|
|
168
|
-
receipt_id=receipt_id,
|
|
169
|
-
await_finality=False,
|
|
170
|
-
)
|
|
171
|
-
|
|
172
|
-
print(verified["status"])
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
##
|
|
233
|
+
console.log(verified.status);
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
```py
|
|
237
|
+
from siglume_direct_request_payment import DirectRequestPaymentClient
|
|
238
|
+
|
|
239
|
+
siglume = DirectRequestPaymentClient(auth_token=buyer_siglume_bearer_token)
|
|
240
|
+
|
|
241
|
+
requirement = siglume.create_payment_requirement(
|
|
242
|
+
merchant="example_merchant",
|
|
243
|
+
amount_minor=1200,
|
|
244
|
+
currency="JPY",
|
|
245
|
+
challenge=challenge_from_merchant_server,
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
if requirement.get("approve_transaction_request"):
|
|
249
|
+
siglume.execute_allowance_transaction(requirement, await_finality=True)
|
|
250
|
+
|
|
251
|
+
payment = siglume.execute_payment_transaction(requirement, await_finality=True)
|
|
252
|
+
receipt_id = str((payment.get("receipt") or {}).get("receipt_id") or "")
|
|
253
|
+
|
|
254
|
+
verified = siglume.verify_payment_requirement(
|
|
255
|
+
requirement["requirement_id"],
|
|
256
|
+
receipt_id=receipt_id,
|
|
257
|
+
await_finality=False,
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
print(verified["status"])
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
## Recurring Payments: Subscription and Scheduled Autopay
|
|
264
|
+
|
|
265
|
+
Beyond one-time checkout, a buyer can authorize recurring payments. The merchant
|
|
266
|
+
approves the price and cadence ONCE by signing a recurring challenge (a distinct
|
|
267
|
+
scheme, so one-time challenges and recurring approvals can never be replayed as
|
|
268
|
+
each other); after that, recurring charges are challenge-free by design — the
|
|
269
|
+
buyer's on-chain payment mandate (frozen payee, amount cap, cadence) is the
|
|
270
|
+
per-charge integrity check.
|
|
271
|
+
|
|
272
|
+
- **Subscription** (`cadence: "monthly"`): Siglume charges the buyer's wallet
|
|
273
|
+
monthly and pays your merchant wallet automatically. First month is charged at
|
|
274
|
+
setup. The buyer can cancel from their Siglume wallet at any time.
|
|
275
|
+
- **Scheduled autopay** (`cadence: "daily"`): the buyer authorizes at most one
|
|
276
|
+
charge per day at a fixed amount and hands you a `schedule_token`; YOUR
|
|
277
|
+
scheduler triggers each occurrence with that token.
|
|
278
|
+
|
|
279
|
+
```ts
|
|
280
|
+
import { createDirectRequestPaymentRecurringChallenge } from "@siglume/direct-request-payment";
|
|
281
|
+
|
|
282
|
+
// Merchant server: approve a JPY 980 monthly subscription once.
|
|
283
|
+
const recurring = await createDirectRequestPaymentRecurringChallenge({
|
|
284
|
+
merchant: "example_merchant",
|
|
285
|
+
amount_minor: 980,
|
|
286
|
+
currency: "JPY",
|
|
287
|
+
cadence: "monthly",
|
|
288
|
+
secret: process.env.SIGLUME_DIRECT_PAYMENT_CHALLENGE_SECRET!,
|
|
289
|
+
nonce: "subscription_setup_4711",
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
// Hand recurring.challenge to the buyer-facing page. The buyer creates the
|
|
293
|
+
// subscription with their Siglume token:
|
|
294
|
+
// POST /v1/market/api-store/direct-payments/subscriptions
|
|
295
|
+
// { merchant, amount_minor, currency, cadence: "monthly", challenge }
|
|
296
|
+
// For scheduled autopay, the buyer instead creates a scheduled auto-pay
|
|
297
|
+
// authorization (mode: "external_402") and gives you the schedule_token.
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
```py
|
|
301
|
+
import os
|
|
302
|
+
|
|
303
|
+
from siglume_direct_request_payment import create_direct_request_payment_recurring_challenge
|
|
304
|
+
|
|
305
|
+
# Merchant server: approve a JPY 980 monthly subscription once.
|
|
306
|
+
recurring = create_direct_request_payment_recurring_challenge(
|
|
307
|
+
merchant="example_merchant",
|
|
308
|
+
amount_minor=980,
|
|
309
|
+
currency="JPY",
|
|
310
|
+
cadence="monthly",
|
|
311
|
+
secret=os.environ["SIGLUME_DIRECT_PAYMENT_CHALLENGE_SECRET"],
|
|
312
|
+
nonce="subscription_setup_4711",
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
# Hand recurring["challenge"] to the buyer-facing page, as in the TS example.
|
|
316
|
+
print(recurring["challenge"])
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
Each recurring challenge is single-use: it authorizes exactly one subscription
|
|
320
|
+
or schedule, bound to the first buyer who redeems it. Issue a fresh challenge
|
|
321
|
+
per setup. The platform fee on recurring charges is your plan's payment fee
|
|
322
|
+
(with the per-payment minimum), frozen at setup.
|
|
323
|
+
|
|
324
|
+
Merchant-facing webhook events: `subscription.created`, `subscription.renewed`
|
|
325
|
+
(each monthly charge), `payment.failed` (renewal failure, with `will_retry` /
|
|
326
|
+
`final_failure` flags), `subscription.cancelled`, and — for each scheduled
|
|
327
|
+
autopay occurrence — the usual `direct_payment.confirmed`.
|
|
328
|
+
|
|
329
|
+
## Webhooks
|
|
176
330
|
|
|
177
331
|
Your merchant system should treat Siglume webhooks as the durable delivery
|
|
178
332
|
signal. Always verify the signature against the raw request body before trusting
|
|
@@ -180,8 +334,8 @@ the payload. Create a marketplace webhook subscription with
|
|
|
180
334
|
`POST /v1/market/webhooks/subscriptions`; the response returns the `whsec_`
|
|
181
335
|
signing secret once.
|
|
182
336
|
|
|
183
|
-
```ts
|
|
184
|
-
import { verifyDirectRequestPaymentWebhook } from "@siglume/direct-request-payment";
|
|
337
|
+
```ts
|
|
338
|
+
import { verifyDirectRequestPaymentWebhook } from "@siglume/direct-request-payment";
|
|
185
339
|
|
|
186
340
|
const { event } = await verifyDirectRequestPaymentWebhook(
|
|
187
341
|
process.env.SIGLUME_WEBHOOK_SECRET!,
|
|
@@ -191,26 +345,26 @@ const { event } = await verifyDirectRequestPaymentWebhook(
|
|
|
191
345
|
|
|
192
346
|
if (event.type === "direct_payment.confirmed") {
|
|
193
347
|
// Mark the order paid if event.data.challenge_hash/order mapping matches.
|
|
194
|
-
}
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
```py
|
|
198
|
-
import os
|
|
199
|
-
|
|
200
|
-
from siglume_direct_request_payment import verify_direct_request_payment_webhook
|
|
201
|
-
|
|
202
|
-
verified = verify_direct_request_payment_webhook(
|
|
203
|
-
os.environ["SIGLUME_WEBHOOK_SECRET"],
|
|
204
|
-
raw_request_body,
|
|
205
|
-
siglume_signature_header,
|
|
206
|
-
)
|
|
207
|
-
|
|
208
|
-
if verified["event"]["type"] == "direct_payment.confirmed":
|
|
209
|
-
# Mark the order paid if event.data.challenge_hash/order mapping matches.
|
|
210
|
-
pass
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
## Security Rules
|
|
348
|
+
}
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
```py
|
|
352
|
+
import os
|
|
353
|
+
|
|
354
|
+
from siglume_direct_request_payment import verify_direct_request_payment_webhook
|
|
355
|
+
|
|
356
|
+
verified = verify_direct_request_payment_webhook(
|
|
357
|
+
os.environ["SIGLUME_WEBHOOK_SECRET"],
|
|
358
|
+
raw_request_body,
|
|
359
|
+
siglume_signature_header,
|
|
360
|
+
)
|
|
361
|
+
|
|
362
|
+
if verified["event"]["type"] == "direct_payment.confirmed":
|
|
363
|
+
# Mark the order paid if event.data.challenge_hash/order mapping matches.
|
|
364
|
+
pass
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
## Security Rules
|
|
214
368
|
|
|
215
369
|
- Keep the challenge secret on the merchant server only.
|
|
216
370
|
- Keep merchant order amount and currency server-authored.
|
|
@@ -224,13 +378,26 @@ if verified["event"]["type"] == "direct_payment.confirmed":
|
|
|
224
378
|
|
|
225
379
|
Read [docs/security.md](./docs/security.md) before going live.
|
|
226
380
|
|
|
381
|
+
## Go-Live Checklist
|
|
382
|
+
|
|
383
|
+
- Run `setupCheckout` with the merchant Siglume JWT.
|
|
384
|
+
- Complete the merchant billing mandate wallet approval if required.
|
|
385
|
+
- Store `SIGLUME_DIRECT_PAYMENT_CHALLENGE_SECRET` only on the merchant server.
|
|
386
|
+
- Store the returned `SIGLUME_WEBHOOK_SECRET` only on the merchant server.
|
|
387
|
+
- Persist `challenge_hash`, `requirement_id`, and fulfillment state per order.
|
|
388
|
+
- Fulfill orders only from verified webhook data, with idempotency.
|
|
389
|
+
- Treat `fee_bps` returned by Siglume as the runtime fee source of truth.
|
|
390
|
+
|
|
227
391
|
## Documentation
|
|
228
392
|
|
|
229
393
|
- [Merchant quickstart](./docs/merchant-quickstart.md)
|
|
230
394
|
- [API reference](./docs/api-reference.md)
|
|
231
395
|
- [Pricing](./docs/pricing.md)
|
|
232
396
|
- [Security guide](./docs/security.md)
|
|
397
|
+
- [Merchant setup example](./examples/setup-merchant.ts)
|
|
233
398
|
- [Express checkout example](./examples/express-checkout.ts)
|
|
399
|
+
- [Japanese launch announcement draft](./docs/announcement-ja.md)
|
|
400
|
+
- [Changelog](./CHANGELOG.md)
|
|
234
401
|
|
|
235
402
|
## License
|
|
236
403
|
|