@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 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
+ [![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
+
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
- ## Install
16
-
17
- ```bash
18
- npm install @siglume/direct-request-payment
19
- ```
20
-
21
- ```bash
22
- pip install siglume-direct-request-payment
23
- ```
24
-
25
- Node.js 18 or later is required for the TypeScript SDK. Python 3.11 or later is
26
- required for the Python SDK.
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
- `DirectRequestPaymentClient` requires the buyer's Siglume bearer token. Do not
40
- use a Developer Portal `cli_` API key with this package.
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
- | 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% |
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
- 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.
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. The listed public pricing is JPY-denominated; USD/USDC merchant
64
- billing requires separately agreed terms.
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
- ## Webhooks
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