@siglume/direct-request-payment 0.1.0 → 0.3.1

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 ADDED
@@ -0,0 +1,61 @@
1
+ # Changelog
2
+
3
+ ## 0.3.1 - 2026-06-12
4
+
5
+ - Docs: scheduled autopay (`cadence: "daily"`) is documented as an approval
6
+ tag, not a once-per-day run limit. Siglume no longer caps scheduled autopay
7
+ at one charge per day; occurrences are bounded by the buyer's per-run,
8
+ daily, and monthly auto-pay budget plus the authorization's `max_runs` /
9
+ expiry. No code or wire-format changes — challenges signed by 0.3.0 verify
10
+ unchanged.
11
+ - Release automation now uses npm and PyPI Trusted Publishing from GitHub
12
+ Actions, so normal releases do not require local npm OTP or PyPI credentials.
13
+
14
+ ## 0.3.0 - 2026-06-12
15
+
16
+ Recurring payment approval release.
17
+
18
+ - Added recurring (subscription / scheduled autopay) merchant approval helpers
19
+ in TypeScript (`createDirectRequestPaymentRecurringChallenge`,
20
+ `createDirectRequestPaymentRecurringChallengeSignature`,
21
+ `verifyDirectRequestPaymentRecurringChallenge`) and Python
22
+ (`create_direct_request_payment_recurring_challenge`,
23
+ `create_direct_request_payment_recurring_challenge_signature`,
24
+ `verify_direct_request_payment_recurring_challenge`).
25
+ - Recurring approvals use a new single-use challenge scheme
26
+ (`siglume-external-402-recurring-v1`) with the cadence (`monthly` for
27
+ subscriptions, `daily` for scheduled autopay) bound into the HMAC, so
28
+ one-time checkout challenges and recurring approvals can never be replayed
29
+ as each other.
30
+ - Documented the recurring payment flow (subscription and scheduled autopay)
31
+ in the README.
32
+ - Updated pricing docs: the Launch plan's free monthly allowance of 100
33
+ payments is retired — Launch is now a flat 1.8% payment fee; the per-payment
34
+ minimum fee is JPY 30 (USD merchants: USD 0.20); JPY/JPYC and USD/USDC
35
+ settlement are both documented as first-class.
36
+
37
+ ## 0.2.0 - 2026-06-12
38
+
39
+ Merchant self-service setup release.
40
+
41
+ - Added TypeScript `DirectRequestPaymentMerchantClient` and Python
42
+ `DirectRequestPaymentMerchantClient`.
43
+ - Added `setupCheckout` / `setup_checkout` to claim a merchant key, prepare a
44
+ billing mandate, and create a webhook subscription from the SDK.
45
+ - Added challenge secret rotation, merchant status lookup, billing mandate
46
+ preparation, and webhook subscription helpers.
47
+ - Updated docs to remove manual onboarding assumptions and clarify merchant JWT
48
+ vs buyer JWT responsibilities.
49
+
50
+ ## 0.1.0 - 2026-06-11
51
+
52
+ Initial public release.
53
+
54
+ - Published TypeScript/JavaScript SDK as `@siglume/direct-request-payment`.
55
+ - Published Python SDK as `siglume-direct-request-payment`.
56
+ - Added merchant challenge helpers, buyer-authenticated Direct Request Payment
57
+ client methods, prepared transaction payload helpers, and webhook signature
58
+ verification helpers.
59
+ - Documented Launch, Starter, Growth, and Pro trial pricing.
60
+ - Documented the distinction from `@siglume/api-sdk` and Developer Portal
61
+ `cli_` API keys.
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Siglume Contributors
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Siglume Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,17 +1,36 @@
1
- # @siglume/direct-request-payment
2
-
3
- Merchant SDK for Siglume Direct Request Payment checkout integrations.
4
-
5
- Use this package when an external EC site, booking service, membership service,
6
- or paid API wants to accept Siglume wallet payments without taking custody of
7
- customer funds.
8
-
9
- This SDK is intentionally separate from `@siglume/api-sdk`:
10
-
11
- - `@siglume/api-sdk` is for publishing agent-facing APIs to the Siglume API Store.
12
- - `@siglume/direct-request-payment` is for external merchants integrating
13
- Siglume Direct Request Payment into their own checkout.
14
-
1
+ # @siglume/direct-request-payment
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@siglume/direct-request-payment.svg)](https://www.npmjs.com/package/@siglume/direct-request-payment)
4
+ [![PyPI version](https://img.shields.io/pypi/v/siglume-direct-request-payment.svg)](https://pypi.org/project/siglume-direct-request-payment/)
5
+
6
+ Merchant SDK for Siglume Direct Request Payment checkout integrations.
7
+
8
+ Use this package when an external EC site, booking service, membership service,
9
+ or paid API wants to accept Siglume wallet payments without taking custody of
10
+ customer funds.
11
+
12
+ This SDK is intentionally separate from `@siglume/api-sdk`:
13
+
14
+ - `@siglume/api-sdk` is for publishing agent-facing APIs to the Siglume API Store.
15
+ - `@siglume/direct-request-payment` is for external merchants integrating
16
+ Siglume Direct Request Payment into their own checkout.
17
+
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
+
15
34
  ## Install
16
35
 
17
36
  ```bash
@@ -24,60 +43,129 @@ pip install siglume-direct-request-payment
24
43
 
25
44
  Node.js 18 or later is required for the TypeScript SDK. Python 3.11 or later is
26
45
  required for the Python SDK.
27
-
28
- ## Current Platform Contract
29
-
30
- The public product name is **Siglume Direct Request Payment**. The current
31
- platform payload still uses the internal mode name `external_402`; this SDK sets
32
- that value for you when creating a payment requirement.
33
-
34
- Payment requirement creation must run in the authenticated buyer's Siglume
35
- context. Your merchant server must not use a merchant secret or API key to
36
- charge a customer wallet. The merchant server creates the signed challenge; the
37
- buyer-facing Siglume payment flow creates and pays the requirement.
38
-
39
- `DirectRequestPaymentClient` requires the buyer's Siglume bearer token. Do not
40
- use a Developer Portal `cli_` API key with this package.
41
-
42
- ## Trial Pricing
43
-
44
- Siglume Direct Request Payment is currently offered with trial-phase merchant
45
- pricing designed for small EC sites, booking services, membership services, paid
46
- APIs, and agent-to-agent payment experiments.
47
-
48
- | Plan | Monthly fee | Payment fee |
49
- | --- | ---: | ---: |
50
- | Launch | JPY 0 | 0% through 100 payments/month, then 1.8% |
51
- | Starter | JPY 980 | 1.0% |
52
- | Growth | JPY 2,980 | 0.7% |
53
- | Pro | JPY 9,800 | 0.5% |
54
-
55
- The minimum fee is JPY 3 for each fee-bearing payment, including Launch-plan
56
- payments after the included monthly allowance. A merchant billing mandate is
57
- required before accepting payments, even on the Launch plan. The API and merchant
58
- registry may still expose the internal plan key `free` for this tier. See
59
- [docs/pricing.md](./docs/pricing.md) for details.
60
-
61
- Per-payment fees are deducted at payment settlement time, so the merchant
62
- receives the net amount. Monthly base fees are collected through the merchant
63
- billing mandate. The listed public pricing is JPY-denominated; USD/USDC merchant
64
- billing requires separately agreed terms.
65
-
66
- ## Merchant Server: Create a Challenge
67
-
46
+
47
+ ## Current Platform Contract
48
+
49
+ The public product name is **Siglume Direct Request Payment**. The current
50
+ platform payload still uses the internal mode name `external_402`; this SDK sets
51
+ that value for you when creating a payment requirement.
52
+
53
+ Payment requirement creation must run in the authenticated buyer's Siglume
54
+ context. Your merchant server must not use a merchant secret or API key to
55
+ charge a customer wallet. The merchant server creates the signed challenge; the
56
+ buyer-facing Siglume payment flow creates and pays the requirement.
57
+
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.
66
+
67
+ ## Trial Pricing
68
+
69
+ Siglume Direct Request Payment is currently offered with trial-phase merchant
70
+ pricing designed for small EC sites, booking services, membership services, paid
71
+ APIs, and agent-to-agent payment experiments.
72
+
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.
77
+
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.
92
+
93
+ Per-payment fees are deducted at payment settlement time, so the merchant
94
+ receives the net amount. Monthly base fees are collected through the merchant
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.
153
+
154
+ ## Merchant Server: Create a Challenge
155
+
68
156
  ```ts
69
157
  import { createDirectRequestPaymentChallenge } from "@siglume/direct-request-payment";
70
-
71
- const challenge = await createDirectRequestPaymentChallenge({
72
- merchant: "example_merchant",
73
- amount_minor: 1200,
74
- currency: "JPY",
75
- secret: process.env.SIGLUME_DIRECT_PAYMENT_CHALLENGE_SECRET!,
76
- nonce: "order_123-attempt_1",
77
- });
78
-
79
- // Return only challenge.challenge to the buyer-facing checkout.
80
- // Never return the challenge secret to the browser.
158
+
159
+ const challenge = await createDirectRequestPaymentChallenge({
160
+ merchant: "example_merchant",
161
+ amount_minor: 1200,
162
+ currency: "JPY",
163
+ secret: process.env.SIGLUME_DIRECT_PAYMENT_CHALLENGE_SECRET!,
164
+ nonce: "order_123-attempt_1",
165
+ });
166
+
167
+ // Return only challenge.challenge to the buyer-facing checkout.
168
+ // Never return the challenge secret to the browser.
81
169
  console.log(challenge.challenge);
82
170
  ```
83
171
 
@@ -98,50 +186,50 @@ print(challenge["challenge"])
98
186
  ```
99
187
 
100
188
  The signed challenge binds:
101
-
102
- - merchant key
103
- - amount in minor units
104
- - currency
105
- - nonce
106
-
107
- Changing any of those values invalidates the challenge.
108
- The nonce must not contain `:` because the current platform challenge format is
109
- `scheme:nonce:signature`.
110
-
111
- ## Buyer Payment Flow
112
-
113
- Use `DirectRequestPaymentClient` only with the authenticated buyer's Siglume
114
- bearer token. `SIGLUME_AUTH_TOKEN` may be used in server-side payment-confirmation
115
- helpers; `SIGLUME_API_KEY` and Developer Portal `cli_` keys are not accepted.
116
-
189
+
190
+ - merchant key
191
+ - amount in minor units
192
+ - currency
193
+ - nonce
194
+
195
+ Changing any of those values invalidates the challenge.
196
+ The nonce must not contain `:` because the current platform challenge format is
197
+ `scheme:nonce:signature`.
198
+
199
+ ## Buyer Payment Flow
200
+
201
+ Use `DirectRequestPaymentClient` only with the authenticated buyer's Siglume
202
+ bearer token. `SIGLUME_AUTH_TOKEN` may be used in server-side payment-confirmation
203
+ helpers; `SIGLUME_API_KEY` and Developer Portal `cli_` keys are not accepted.
204
+
117
205
  ```ts
118
206
  import { DirectRequestPaymentClient } from "@siglume/direct-request-payment";
119
-
120
- const siglume = new DirectRequestPaymentClient({
121
- auth_token: buyerSiglumeBearerToken,
122
- });
123
-
124
- const requirement = await siglume.createPaymentRequirement({
125
- merchant: "example_merchant",
126
- amount_minor: 1200,
127
- currency: "JPY",
128
- challenge: challengeFromMerchantServer,
129
- });
130
-
131
- if (requirement.approve_transaction_request) {
132
- await siglume.executeAllowanceTransaction(requirement, { await_finality: true });
133
- }
134
-
135
- const payment = await siglume.executePaymentTransaction(requirement, {
136
- await_finality: true,
137
- });
138
-
139
- const receiptId = String(payment.receipt?.receipt_id ?? "");
140
- const verified = await siglume.verifyPaymentRequirement(requirement.requirement_id, {
141
- receipt_id: receiptId,
142
- await_finality: false,
143
- });
144
-
207
+
208
+ const siglume = new DirectRequestPaymentClient({
209
+ auth_token: buyerSiglumeBearerToken,
210
+ });
211
+
212
+ const requirement = await siglume.createPaymentRequirement({
213
+ merchant: "example_merchant",
214
+ amount_minor: 1200,
215
+ currency: "JPY",
216
+ challenge: challengeFromMerchantServer,
217
+ });
218
+
219
+ if (requirement.approve_transaction_request) {
220
+ await siglume.executeAllowanceTransaction(requirement, { await_finality: true });
221
+ }
222
+
223
+ const payment = await siglume.executePaymentTransaction(requirement, {
224
+ await_finality: true,
225
+ });
226
+
227
+ const receiptId = String(payment.receipt?.receipt_id ?? "");
228
+ const verified = await siglume.verifyPaymentRequirement(requirement.requirement_id, {
229
+ receipt_id: receiptId,
230
+ await_finality: false,
231
+ });
232
+
145
233
  console.log(verified.status);
146
234
  ```
147
235
 
@@ -172,25 +260,93 @@ verified = siglume.verify_payment_requirement(
172
260
  print(verified["status"])
173
261
  ```
174
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 recurring product tag ONCE by signing a recurring
267
+ challenge (a distinct scheme, so one-time challenges and recurring approvals can
268
+ never be replayed as each other); after that, recurring charges are
269
+ challenge-free by design. Subscriptions are bounded by the buyer's mandate;
270
+ scheduled autopay is bounded by the buyer's per-run, daily, and monthly
271
+ auto-pay budget.
272
+
273
+ - **Subscription** (`cadence: "monthly"`): Siglume charges the buyer's wallet
274
+ monthly and pays your merchant wallet automatically. First month is charged at
275
+ setup. The buyer can cancel from their Siglume wallet at any time.
276
+ - **Scheduled autopay** (`cadence: "daily"`): `daily` is the approval tag for
277
+ merchant-triggered scheduled autopay, not a run-count limiter. The
278
+ buyer authorizes the per-run amount and budget envelope, then hands you a
279
+ `schedule_token`; YOUR scheduler triggers each occurrence with that token.
280
+
281
+ ```ts
282
+ import { createDirectRequestPaymentRecurringChallenge } from "@siglume/direct-request-payment";
283
+
284
+ // Merchant server: approve a JPY 980 monthly subscription once.
285
+ const recurring = await createDirectRequestPaymentRecurringChallenge({
286
+ merchant: "example_merchant",
287
+ amount_minor: 980,
288
+ currency: "JPY",
289
+ cadence: "monthly",
290
+ secret: process.env.SIGLUME_DIRECT_PAYMENT_CHALLENGE_SECRET!,
291
+ nonce: "subscription_setup_4711",
292
+ });
293
+
294
+ // Hand recurring.challenge to the buyer-facing page. The buyer creates the
295
+ // subscription with their Siglume token:
296
+ // POST /v1/market/api-store/direct-payments/subscriptions
297
+ // { merchant, amount_minor, currency, cadence: "monthly", challenge }
298
+ // For scheduled autopay, the buyer instead creates a scheduled auto-pay
299
+ // authorization (mode: "external_402") and gives you the schedule_token.
300
+ ```
301
+
302
+ ```py
303
+ import os
304
+
305
+ from siglume_direct_request_payment import create_direct_request_payment_recurring_challenge
306
+
307
+ # Merchant server: approve a JPY 980 monthly subscription once.
308
+ recurring = create_direct_request_payment_recurring_challenge(
309
+ merchant="example_merchant",
310
+ amount_minor=980,
311
+ currency="JPY",
312
+ cadence="monthly",
313
+ secret=os.environ["SIGLUME_DIRECT_PAYMENT_CHALLENGE_SECRET"],
314
+ nonce="subscription_setup_4711",
315
+ )
316
+
317
+ # Hand recurring["challenge"] to the buyer-facing page, as in the TS example.
318
+ print(recurring["challenge"])
319
+ ```
320
+
321
+ Each recurring challenge is single-use: it authorizes exactly one subscription
322
+ or schedule, bound to the first buyer who redeems it. Issue a fresh challenge
323
+ per setup. The platform fee on recurring charges is your plan's payment fee
324
+ (with the per-payment minimum), frozen at setup.
325
+
326
+ Merchant-facing webhook events: `subscription.created`, `subscription.renewed`
327
+ (each monthly charge), `payment.failed` (renewal failure, with `will_retry` /
328
+ `final_failure` flags), `subscription.cancelled`, and — for each scheduled
329
+ autopay occurrence — the usual `direct_payment.confirmed`.
330
+
175
331
  ## Webhooks
176
-
177
- Your merchant system should treat Siglume webhooks as the durable delivery
178
- signal. Always verify the signature against the raw request body before trusting
179
- the payload. Create a marketplace webhook subscription with
180
- `POST /v1/market/webhooks/subscriptions`; the response returns the `whsec_`
181
- signing secret once.
182
-
332
+
333
+ Your merchant system should treat Siglume webhooks as the durable delivery
334
+ signal. Always verify the signature against the raw request body before trusting
335
+ the payload. Create a marketplace webhook subscription with
336
+ `POST /v1/market/webhooks/subscriptions`; the response returns the `whsec_`
337
+ signing secret once.
338
+
183
339
  ```ts
184
340
  import { verifyDirectRequestPaymentWebhook } from "@siglume/direct-request-payment";
185
-
186
- const { event } = await verifyDirectRequestPaymentWebhook(
187
- process.env.SIGLUME_WEBHOOK_SECRET!,
188
- rawRequestBody,
189
- request.headers["siglume-signature"],
190
- );
191
-
192
- if (event.type === "direct_payment.confirmed") {
193
- // Mark the order paid if event.data.challenge_hash/order mapping matches.
341
+
342
+ const { event } = await verifyDirectRequestPaymentWebhook(
343
+ process.env.SIGLUME_WEBHOOK_SECRET!,
344
+ rawRequestBody,
345
+ request.headers["siglume-signature"],
346
+ );
347
+
348
+ if (event.type === "direct_payment.confirmed") {
349
+ // Mark the order paid if event.data.challenge_hash/order mapping matches.
194
350
  }
195
351
  ```
196
352
 
@@ -211,27 +367,40 @@ if verified["event"]["type"] == "direct_payment.confirmed":
211
367
  ```
212
368
 
213
369
  ## Security Rules
214
-
215
- - Keep the challenge secret on the merchant server only.
216
- - Keep merchant order amount and currency server-authored.
217
- - Use one nonce per order payment attempt.
218
- - Store `challenge_hash` with the order and reject mismatches.
219
- - Make order fulfillment idempotent by `requirement_id` and order id.
220
- - Verify webhook signatures against the raw body.
221
- - Do not use a merchant token to charge a customer wallet.
222
- - Do not treat Direct Request Payment as stored value, prepaid points, escrow, or
223
- a platform balance.
224
-
225
- Read [docs/security.md](./docs/security.md) before going live.
226
-
227
- ## Documentation
228
-
229
- - [Merchant quickstart](./docs/merchant-quickstart.md)
230
- - [API reference](./docs/api-reference.md)
231
- - [Pricing](./docs/pricing.md)
232
- - [Security guide](./docs/security.md)
233
- - [Express checkout example](./examples/express-checkout.ts)
234
-
235
- ## License
236
-
237
- MIT
370
+
371
+ - Keep the challenge secret on the merchant server only.
372
+ - Keep merchant order amount and currency server-authored.
373
+ - Use one nonce per order payment attempt.
374
+ - Store `challenge_hash` with the order and reject mismatches.
375
+ - Make order fulfillment idempotent by `requirement_id` and order id.
376
+ - Verify webhook signatures against the raw body.
377
+ - Do not use a merchant token to charge a customer wallet.
378
+ - Do not treat Direct Request Payment as stored value, prepaid points, escrow, or
379
+ a platform balance.
380
+
381
+ Read [docs/security.md](./docs/security.md) before going live.
382
+
383
+ ## Go-Live Checklist
384
+
385
+ - Run `setupCheckout` with the merchant Siglume JWT.
386
+ - Complete the merchant billing mandate wallet approval if required.
387
+ - Store `SIGLUME_DIRECT_PAYMENT_CHALLENGE_SECRET` only on the merchant server.
388
+ - Store the returned `SIGLUME_WEBHOOK_SECRET` only on the merchant server.
389
+ - Persist `challenge_hash`, `requirement_id`, and fulfillment state per order.
390
+ - Fulfill orders only from verified webhook data, with idempotency.
391
+ - Treat `fee_bps` returned by Siglume as the runtime fee source of truth.
392
+
393
+ ## Documentation
394
+
395
+ - [Merchant quickstart](./docs/merchant-quickstart.md)
396
+ - [API reference](./docs/api-reference.md)
397
+ - [Pricing](./docs/pricing.md)
398
+ - [Security guide](./docs/security.md)
399
+ - [Merchant setup example](./examples/setup-merchant.ts)
400
+ - [Express checkout example](./examples/express-checkout.ts)
401
+ - [Japanese launch announcement draft](./docs/announcement-ja.md)
402
+ - [Changelog](./CHANGELOG.md)
403
+
404
+ ## License
405
+
406
+ MIT