@siglume/direct-request-payment 0.4.1 → 0.4.2
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 +29 -0
- package/README.md +44 -0
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/docs/api-reference.md +334 -18
- package/docs/merchant-quickstart.md +27 -0
- package/package.json +1 -1
package/docs/api-reference.md
CHANGED
|
@@ -80,10 +80,79 @@ Returns:
|
|
|
80
80
|
`nonce` must not contain `:` because the platform challenge string is delimited
|
|
81
81
|
as `scheme:nonce:signature`.
|
|
82
82
|
|
|
83
|
+
## `createDirectRequestPaymentChallengeSignature(secret, input)` / `create_direct_request_payment_challenge_signature(...)`
|
|
84
|
+
|
|
85
|
+
Returns just the HMAC-SHA256 hex digest (no `scheme:nonce:signature` wrapper),
|
|
86
|
+
for callers who assemble the challenge string themselves. This is the primitive
|
|
87
|
+
that `createDirectRequestPaymentChallenge` calls internally. The HMAC material is
|
|
88
|
+
`merchant:amount_minor:currency:nonce`.
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
const signature = await createDirectRequestPaymentChallengeSignature(secret, {
|
|
92
|
+
merchant: "example_merchant",
|
|
93
|
+
amount_minor: 1200,
|
|
94
|
+
currency: "JPY",
|
|
95
|
+
nonce: "order_123-attempt_1",
|
|
96
|
+
});
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
```py
|
|
100
|
+
signature = create_direct_request_payment_challenge_signature(
|
|
101
|
+
secret=secret,
|
|
102
|
+
merchant="example_merchant",
|
|
103
|
+
amount_minor=1200,
|
|
104
|
+
currency="JPY",
|
|
105
|
+
nonce="order_123-attempt_1",
|
|
106
|
+
)
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
In TypeScript the secret is the first positional argument and the rest are an
|
|
110
|
+
object. In Python every argument is keyword-only:
|
|
111
|
+
`create_direct_request_payment_challenge_signature(*, secret, merchant, amount_minor, currency, nonce)`.
|
|
112
|
+
Returns a `string` (TS) / `str` (Py).
|
|
113
|
+
|
|
83
114
|
## `verifyDirectRequestPaymentChallenge(secret, input)` / `verify_direct_request_payment_challenge(...)`
|
|
84
115
|
|
|
85
116
|
Verifies a challenge against merchant, amount, currency, and secret. This is
|
|
86
|
-
useful in tests and internal checkout assertions.
|
|
117
|
+
useful in tests and internal checkout assertions. Returns `boolean` (TS) /
|
|
118
|
+
`bool` (Py) — `true` only when the challenge scheme matches and the recomputed
|
|
119
|
+
signature is a timing-safe match.
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
const ok = await verifyDirectRequestPaymentChallenge(secret, {
|
|
123
|
+
merchant: "example_merchant",
|
|
124
|
+
amount_minor: 1200,
|
|
125
|
+
currency: "JPY",
|
|
126
|
+
challenge: challengeString,
|
|
127
|
+
});
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
In TypeScript the secret is positional and the rest is an object
|
|
131
|
+
(`verifyDirectRequestPaymentChallenge(secret, { merchant, amount_minor, currency, challenge })`).
|
|
132
|
+
In Python every argument is keyword-only:
|
|
133
|
+
|
|
134
|
+
```py
|
|
135
|
+
ok = verify_direct_request_payment_challenge(
|
|
136
|
+
secret=secret,
|
|
137
|
+
merchant="example_merchant",
|
|
138
|
+
amount_minor=1200,
|
|
139
|
+
currency="JPY",
|
|
140
|
+
challenge=challenge_string,
|
|
141
|
+
)
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## `parseDirectRequestPaymentChallenge(challenge)` / `parse_direct_request_payment_challenge(challenge)`
|
|
145
|
+
|
|
146
|
+
Splits a `scheme:nonce:signature` challenge string into its parts. Throws
|
|
147
|
+
`SiglumeDirectRequestPaymentError` (TS) / `DirectRequestPaymentError` (Py) when
|
|
148
|
+
the string is not exactly three non-empty colon-delimited parts. The `challenge`
|
|
149
|
+
argument is positional in both languages.
|
|
150
|
+
|
|
151
|
+
Returns:
|
|
152
|
+
|
|
153
|
+
- `scheme`
|
|
154
|
+
- `nonce`
|
|
155
|
+
- `signature`
|
|
87
156
|
|
|
88
157
|
## `createDirectRequestPaymentRecurringChallenge(input)` / `create_direct_request_payment_recurring_challenge(...)`
|
|
89
158
|
|
|
@@ -137,10 +206,59 @@ monthly auto-pay budget.
|
|
|
137
206
|
|
|
138
207
|
Returns the same fields as the one-time challenge helper, plus `cadence`.
|
|
139
208
|
|
|
209
|
+
## `createDirectRequestPaymentRecurringChallengeSignature(secret, input)` / `create_direct_request_payment_recurring_challenge_signature(...)`
|
|
210
|
+
|
|
211
|
+
Returns just the HMAC-SHA256 hex digest for a recurring approval, for callers who
|
|
212
|
+
assemble the challenge string themselves. This is the primitive that
|
|
213
|
+
`createDirectRequestPaymentRecurringChallenge` calls internally. The HMAC
|
|
214
|
+
material is `merchant:amount_minor:currency:cadence:nonce` and must stay
|
|
215
|
+
byte-identical to the server's recurring-challenge signer.
|
|
216
|
+
|
|
217
|
+
```ts
|
|
218
|
+
const signature = await createDirectRequestPaymentRecurringChallengeSignature(secret, {
|
|
219
|
+
merchant: "example_merchant",
|
|
220
|
+
amount_minor: 980,
|
|
221
|
+
currency: "JPY",
|
|
222
|
+
cadence: "monthly",
|
|
223
|
+
nonce: "subscription_setup_4711",
|
|
224
|
+
});
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
```py
|
|
228
|
+
signature = create_direct_request_payment_recurring_challenge_signature(
|
|
229
|
+
secret=secret,
|
|
230
|
+
merchant="example_merchant",
|
|
231
|
+
amount_minor=980,
|
|
232
|
+
currency="JPY",
|
|
233
|
+
cadence="monthly",
|
|
234
|
+
nonce="subscription_setup_4711",
|
|
235
|
+
)
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
In TypeScript the secret is positional and the rest is an object. In Python every
|
|
239
|
+
argument is keyword-only:
|
|
240
|
+
`create_direct_request_payment_recurring_challenge_signature(*, secret, merchant, amount_minor, currency, cadence, nonce)`.
|
|
241
|
+
Returns a `string` (TS) / `str` (Py).
|
|
242
|
+
|
|
140
243
|
## `verifyDirectRequestPaymentRecurringChallenge(secret, input)` / `verify_direct_request_payment_recurring_challenge(...)`
|
|
141
244
|
|
|
142
245
|
Verifies a recurring approval challenge against merchant, amount, currency,
|
|
143
|
-
cadence, and secret.
|
|
246
|
+
cadence, and secret. Returns `boolean` (TS) / `bool` (Py).
|
|
247
|
+
|
|
248
|
+
In TypeScript the secret is positional and the rest is an object
|
|
249
|
+
(`verifyDirectRequestPaymentRecurringChallenge(secret, { merchant, amount_minor, currency, cadence, challenge })`).
|
|
250
|
+
In Python every argument is keyword-only:
|
|
251
|
+
|
|
252
|
+
```py
|
|
253
|
+
ok = verify_direct_request_payment_recurring_challenge(
|
|
254
|
+
secret=secret,
|
|
255
|
+
merchant="example_merchant",
|
|
256
|
+
amount_minor=980,
|
|
257
|
+
currency="JPY",
|
|
258
|
+
cadence="monthly",
|
|
259
|
+
challenge=challenge_string,
|
|
260
|
+
)
|
|
261
|
+
```
|
|
144
262
|
|
|
145
263
|
## `directRequestPaymentChallengeHash(challenge)` / `direct_request_payment_challenge_hash(...)`
|
|
146
264
|
|
|
@@ -180,7 +298,9 @@ Input:
|
|
|
180
298
|
- `merchant`: self-service merchant key, 3-64 chars using lowercase letters,
|
|
181
299
|
numbers, `_`, or `-`
|
|
182
300
|
- `display_name`: optional public merchant name
|
|
183
|
-
- `billing_plan`: `launch`, `starter`, `growth`, or `pro`
|
|
301
|
+
- `billing_plan`: `launch`, `starter`, `growth`, or `pro` (default `launch`). The
|
|
302
|
+
legacy key `free` is also accepted as a compatibility input and maps to the
|
|
303
|
+
Launch tier; prefer `launch` in new code.
|
|
184
304
|
- `billing_currency`: `JPY`; `USD` requires agreed USD/USDC billing terms
|
|
185
305
|
- `webhook_callback_url`: HTTPS callback URL for signed payment events
|
|
186
306
|
- `max_amount_minor`: optional billing mandate cap
|
|
@@ -191,6 +311,21 @@ Input:
|
|
|
191
311
|
absolute origin such as `https://shop.example.com`; entries are normalized to
|
|
192
312
|
bare, lowercased origins and deduped.
|
|
193
313
|
|
|
314
|
+
In addition to the `setupMerchant` inputs above, `setupCheckout` accepts these
|
|
315
|
+
orchestration toggles:
|
|
316
|
+
|
|
317
|
+
- `prepare_billing_mandate`: default `true`. When `false`, the billing mandate
|
|
318
|
+
step is skipped and `billing_mandate` in the result is `null`.
|
|
319
|
+
- `create_webhook_subscription`: optional. When omitted, a webhook subscription
|
|
320
|
+
is created only if `webhook_callback_url` is set. Set `false` to skip webhook
|
|
321
|
+
creation even when a callback URL is present (TS uses `?? Boolean(webhook_callback_url)`;
|
|
322
|
+
Py defaults to `bool(webhook_callback_url)`).
|
|
323
|
+
- `webhook_event_types`: optional `string[]` of event types for the created
|
|
324
|
+
subscription. When omitted the subscription defaults to
|
|
325
|
+
`direct_payment.confirmed` and `direct_payment.spent`.
|
|
326
|
+
- `webhook_description`: optional description for the created subscription;
|
|
327
|
+
defaults to `"<merchant> Direct Request Payment"`.
|
|
328
|
+
|
|
194
329
|
Returns:
|
|
195
330
|
|
|
196
331
|
- `merchant`: merchant account setup response
|
|
@@ -291,7 +426,7 @@ Calls:
|
|
|
291
426
|
GET /v1/sdrp/direct-payments/checkout-sessions/{session_id}
|
|
292
427
|
```
|
|
293
428
|
|
|
294
|
-
Returns a
|
|
429
|
+
Returns a `HostedCheckoutSession` status object with:
|
|
295
430
|
|
|
296
431
|
- `session_id`
|
|
297
432
|
- `merchant`
|
|
@@ -301,13 +436,19 @@ Returns a session status object with:
|
|
|
301
436
|
- `status`: one of `open`, `authenticated`, `paid`, `expired`, `cancelled`,
|
|
302
437
|
`failed`
|
|
303
438
|
- `challenge_hash`
|
|
304
|
-
- `requirement_id`
|
|
439
|
+
- `requirement_id` (nullable until a requirement is created)
|
|
305
440
|
- `success_url`
|
|
306
441
|
- `cancel_url`
|
|
307
|
-
- `expires_at`
|
|
308
|
-
- `
|
|
442
|
+
- `expires_at` (nullable)
|
|
443
|
+
- `authenticated_at` (nullable; set when the shopper signs into Siglume)
|
|
444
|
+
- `paid_at` (nullable; set when the payment confirms)
|
|
445
|
+
- `cancelled_at` (nullable; set when the shopper cancels)
|
|
446
|
+
- `created_at` (nullable)
|
|
309
447
|
- `metadata_jsonb`
|
|
310
448
|
|
|
449
|
+
The TS `HostedCheckoutSession` interface also carries an index signature, so the
|
|
450
|
+
server may include additional pass-through fields.
|
|
451
|
+
|
|
311
452
|
### `getMerchant(merchant)` / `get_merchant(merchant)`
|
|
312
453
|
|
|
313
454
|
Calls:
|
|
@@ -401,6 +542,61 @@ Input:
|
|
|
401
542
|
- `allowance_amount_minor`: optional positive integer
|
|
402
543
|
- `metadata`: optional JSON object
|
|
403
544
|
|
|
545
|
+
### `getPaymentRequirement(requirement_id)` / `get_payment_requirement(requirement_id)`
|
|
546
|
+
|
|
547
|
+
Calls:
|
|
548
|
+
|
|
549
|
+
```text
|
|
550
|
+
GET /v1/sdrp/direct-payments/requirements/{requirement_id}
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
Fetches the current state of a payment requirement (status, `transaction_request`,
|
|
554
|
+
`approve_transaction_request`, `chain_receipt_id`, etc.) by id. The
|
|
555
|
+
`requirement_id` argument is positional in both languages. Returns the same
|
|
556
|
+
requirement object shape as `createPaymentRequirement`.
|
|
557
|
+
|
|
558
|
+
```ts
|
|
559
|
+
const requirement = await siglume.getPaymentRequirement(requirementId);
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
```py
|
|
563
|
+
requirement = siglume.get_payment_requirement(requirement_id)
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
### `executePreparedTransaction(payload)` / `execute_prepared_transaction(payload)`
|
|
567
|
+
|
|
568
|
+
Calls:
|
|
569
|
+
|
|
570
|
+
```text
|
|
571
|
+
POST /v1/market/web3/transactions/execute-prepared
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
The raw prepared-transaction executor. It posts a prepared-transaction payload
|
|
575
|
+
(`transaction_request`, `receipt_kind`, `reference_type`, `reference_id`,
|
|
576
|
+
`metadata`, `await_finality`) to the marketplace web3 route and returns the
|
|
577
|
+
execution result (`{ receipt?, finalization?, ... }`). The `payload` argument is
|
|
578
|
+
positional in both languages.
|
|
579
|
+
|
|
580
|
+
`executePaymentTransaction` / `execute_payment_transaction` and
|
|
581
|
+
`executeAllowanceTransaction` / `execute_allowance_transaction` are convenience
|
|
582
|
+
wrappers over this method: they build the payload from the requirement (via
|
|
583
|
+
[`buildPaymentExecutionPayload`](#payload-builders) /
|
|
584
|
+
[`buildAllowanceExecutionPayload`](#payload-builders)) and call
|
|
585
|
+
`executePreparedTransaction` for you. Call `executePreparedTransaction` directly
|
|
586
|
+
only when you build the payload yourself.
|
|
587
|
+
|
|
588
|
+
```ts
|
|
589
|
+
const result = await siglume.executePreparedTransaction(
|
|
590
|
+
buildPaymentExecutionPayload(requirement, { await_finality: true }),
|
|
591
|
+
);
|
|
592
|
+
```
|
|
593
|
+
|
|
594
|
+
```py
|
|
595
|
+
result = siglume.execute_prepared_transaction(
|
|
596
|
+
build_payment_execution_payload(requirement, await_finality=True),
|
|
597
|
+
)
|
|
598
|
+
```
|
|
599
|
+
|
|
404
600
|
### `executeAllowanceTransaction(requirement)` / `execute_allowance_transaction(...)`
|
|
405
601
|
|
|
406
602
|
Executes `requirement.approve_transaction_request` through:
|
|
@@ -433,19 +629,139 @@ Input may include:
|
|
|
433
629
|
- `await_timeout_seconds`
|
|
434
630
|
- `await_poll_seconds`
|
|
435
631
|
|
|
632
|
+
## Payload Builders
|
|
633
|
+
|
|
634
|
+
These pure functions build the `execute-prepared` payload from a payment
|
|
635
|
+
requirement, for callers who execute the transaction themselves (rather than via
|
|
636
|
+
the `executePaymentTransaction` / `executeAllowanceTransaction` wrappers). They
|
|
637
|
+
make no network calls.
|
|
638
|
+
|
|
639
|
+
### `buildPaymentExecutionPayload(requirement, options)` / `build_payment_execution_payload(...)`
|
|
640
|
+
|
|
641
|
+
Builds the payment-transaction payload from `requirement.transaction_request`
|
|
642
|
+
with `receipt_kind = "sdrp_direct_payment"`.
|
|
643
|
+
|
|
644
|
+
In TypeScript `options` is an optional object `{ await_finality?, metadata? }`.
|
|
645
|
+
In Python the options are keyword-only:
|
|
646
|
+
`build_payment_execution_payload(requirement, *, await_finality=False, metadata=None)`.
|
|
647
|
+
Returns the prepared-transaction payload object.
|
|
648
|
+
|
|
649
|
+
### `buildAllowanceExecutionPayload(requirement, options)` / `build_allowance_execution_payload(...)`
|
|
650
|
+
|
|
651
|
+
Builds the allowance/approval-transaction payload from
|
|
652
|
+
`requirement.approve_transaction_request` with
|
|
653
|
+
`receipt_kind = "sdrp_direct_payment_allowance"`. Throws
|
|
654
|
+
`SiglumeDirectRequestPaymentError` (TS) / `DirectRequestPaymentError` (Py) when
|
|
655
|
+
the requirement carries no allowance approval transaction. Same options shape as
|
|
656
|
+
`buildPaymentExecutionPayload`.
|
|
657
|
+
|
|
658
|
+
### `buildPreparedTransactionExecutionPayload(requirement, transaction_request, options)` / `build_prepared_transaction_execution_payload(...)`
|
|
659
|
+
|
|
660
|
+
The lower-level builder both of the above call. It merges
|
|
661
|
+
`transaction_request.metadata_jsonb` with any `options.metadata`, and sets
|
|
662
|
+
`reference_type = "sdrp_direct_payment_requirement"` and `reference_id =
|
|
663
|
+
requirement.requirement_id`.
|
|
664
|
+
|
|
665
|
+
In TypeScript `options` is required and must include `receipt_kind`:
|
|
666
|
+
`{ receipt_kind, await_finality?, metadata? }`. In Python the third argument is
|
|
667
|
+
the `transaction_request` and the rest are keyword-only:
|
|
668
|
+
`build_prepared_transaction_execution_payload(requirement, transaction_request, *, receipt_kind, await_finality=False, metadata=None)`.
|
|
669
|
+
Returns the prepared-transaction payload object.
|
|
670
|
+
|
|
436
671
|
## Webhook Helpers
|
|
437
672
|
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
- `
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
`
|
|
448
|
-
|
|
673
|
+
### `computeWebhookSignature(secret, body, options)` / `compute_webhook_signature(secret, body, *, timestamp)`
|
|
674
|
+
|
|
675
|
+
Returns the bare HMAC-SHA256 hex digest over `"<timestamp>.<body>"`. This is the
|
|
676
|
+
primitive `buildWebhookSignatureHeader` / `verifyWebhookSignature` use. In
|
|
677
|
+
TypeScript `options` is `{ timestamp: number }`; in Python `timestamp` is a
|
|
678
|
+
keyword-only `int`. `body` may be raw bytes, a string, or a JSON object.
|
|
679
|
+
|
|
680
|
+
### `buildWebhookSignatureHeader(secret, body, options)` / `build_webhook_signature_header(secret, body, *, timestamp=None)`
|
|
681
|
+
|
|
682
|
+
Returns a `t=<timestamp>,v1=<signature>` header string. Mainly for tests /
|
|
683
|
+
mocking inbound webhooks. In TypeScript `options` is an optional
|
|
684
|
+
`{ timestamp?: number }` (defaults to now); in Python `timestamp` is a
|
|
685
|
+
keyword-only optional `int`.
|
|
686
|
+
|
|
687
|
+
### `verifyWebhookSignature(secret, body, signature_header, options)` / `verify_webhook_signature(secret, body, signature_header, *, tolerance_seconds=300, now=None)`
|
|
688
|
+
|
|
689
|
+
Verifies the `Siglume-Signature` header against the raw `body`. Throws
|
|
690
|
+
`SiglumeWebhookSignatureError` (TS) / `SiglumeWebhookSignatureError` (Py) when
|
|
691
|
+
the timestamp is outside tolerance or the signature does not match. In TypeScript
|
|
692
|
+
`options` is `{ tolerance_seconds?, now? }`; in Python those are keyword-only
|
|
693
|
+
(`tolerance_seconds` defaults to `DEFAULT_WEBHOOK_TOLERANCE_SECONDS` = 300).
|
|
694
|
+
Returns `{ timestamp, signature }`.
|
|
695
|
+
|
|
696
|
+
### `parseDirectRequestPaymentWebhookEvent(payload)` / `parse_direct_request_payment_webhook_event(payload)`
|
|
697
|
+
|
|
698
|
+
Validates and normalizes a parsed webhook event object (requires `id`, `type`,
|
|
699
|
+
`api_version`, `occurred_at`, and an object `data`). Throws
|
|
700
|
+
`SiglumeWebhookPayloadError` on a malformed event, or when a
|
|
701
|
+
`direct_payment.confirmed` event does not carry `data.mode = "external_402"`. The
|
|
702
|
+
`payload` argument is positional in both languages.
|
|
703
|
+
|
|
704
|
+
### `verifyDirectRequestPaymentWebhook(secret, body, signature_header, options)` / `verify_direct_request_payment_webhook(secret, body, signature_header, *, tolerance_seconds=300, now=None)`
|
|
705
|
+
|
|
706
|
+
Verifies the signature and parses the event in one call. Returns
|
|
707
|
+
`{ event, verification }` (TS) / `{"event": ..., "verification": ...}` (Py). Same
|
|
708
|
+
options shape as `verifyWebhookSignature` (keyword-only in Python).
|
|
709
|
+
|
|
710
|
+
Webhook-verification trio (typical inbound webhook handler):
|
|
711
|
+
|
|
712
|
+
```ts
|
|
713
|
+
import { verifyDirectRequestPaymentWebhook } from "@siglume/direct-request-payment";
|
|
714
|
+
|
|
715
|
+
const { event, verification } = await verifyDirectRequestPaymentWebhook(
|
|
716
|
+
process.env.SIGLUME_WEBHOOK_SECRET!,
|
|
717
|
+
rawRequestBody, // the RAW body bytes/string, not re-stringified JSON
|
|
718
|
+
request.headers["siglume-signature"],
|
|
719
|
+
);
|
|
720
|
+
// event.type === "direct_payment.confirmed" -> fulfill once; verification.timestamp is the signed time
|
|
721
|
+
```
|
|
722
|
+
|
|
723
|
+
```py
|
|
724
|
+
from siglume_direct_request_payment import verify_direct_request_payment_webhook
|
|
725
|
+
|
|
726
|
+
verified = verify_direct_request_payment_webhook(
|
|
727
|
+
os.environ["SIGLUME_WEBHOOK_SECRET"],
|
|
728
|
+
raw_request_body, # the RAW body bytes/string
|
|
729
|
+
siglume_signature_header,
|
|
730
|
+
)
|
|
731
|
+
event = verified["event"]
|
|
732
|
+
# event["type"] == "direct_payment.confirmed" -> fulfill once
|
|
733
|
+
```
|
|
734
|
+
|
|
735
|
+
## Exported Constants
|
|
736
|
+
|
|
737
|
+
Both packages export these importable constants:
|
|
738
|
+
|
|
739
|
+
| Constant | Value |
|
|
740
|
+
| --- | --- |
|
|
741
|
+
| `DEFAULT_SIGLUME_API_BASE` | `https://siglume.com/v1` |
|
|
742
|
+
| `DIRECT_REQUEST_PAYMENT_CHALLENGE_SCHEME` | `siglume-external-402-v1` |
|
|
743
|
+
| `DIRECT_REQUEST_PAYMENT_RECURRING_CHALLENGE_SCHEME` | `siglume-external-402-recurring-v1` |
|
|
744
|
+
| `DIRECT_REQUEST_PAYMENT_MODE` | `external_402` |
|
|
745
|
+
| `DIRECT_REQUEST_PAYMENT_RECEIPT_KIND` | `sdrp_direct_payment` |
|
|
746
|
+
| `DIRECT_REQUEST_PAYMENT_ALLOWANCE_RECEIPT_KIND` | `sdrp_direct_payment_allowance` |
|
|
747
|
+
| `DIRECT_REQUEST_PAYMENT_REFERENCE_TYPE` | `sdrp_direct_payment_requirement` |
|
|
748
|
+
| `DEFAULT_WEBHOOK_TOLERANCE_SECONDS` | `300` |
|
|
749
|
+
|
|
750
|
+
The `external_402` / `siglume-external-402-*` values are legacy wire-compat
|
|
751
|
+
identifiers, not public product names (see the README "Compatibility Notes").
|
|
752
|
+
|
|
753
|
+
## Aliases
|
|
754
|
+
|
|
755
|
+
For legacy wire-compat naming, the following exported names are aliases of the
|
|
756
|
+
preferred `DirectRequestPayment*` functions. They are identical functions; new
|
|
757
|
+
code should prefer the `DirectRequestPayment*` names.
|
|
758
|
+
|
|
759
|
+
| Alias (TS) | Alias (Py) | Preferred function |
|
|
760
|
+
| --- | --- | --- |
|
|
761
|
+
| `createExternal402Challenge` | `create_external_402_challenge` | `createDirectRequestPaymentChallenge` / `create_direct_request_payment_challenge` |
|
|
762
|
+
| `verifyExternal402Challenge` | `verify_external_402_challenge` | `verifyDirectRequestPaymentChallenge` / `verify_direct_request_payment_challenge` |
|
|
763
|
+
| `createExternal402RecurringChallenge` | `create_external_402_recurring_challenge` | `createDirectRequestPaymentRecurringChallenge` / `create_direct_request_payment_recurring_challenge` |
|
|
764
|
+
| `verifyExternal402RecurringChallenge` | `verify_external_402_recurring_challenge` | `verifyDirectRequestPaymentRecurringChallenge` / `verify_direct_request_payment_recurring_challenge` |
|
|
449
765
|
|
|
450
766
|
## Errors
|
|
451
767
|
|
|
@@ -361,6 +361,26 @@ siglume.verify_payment_requirement(
|
|
|
361
361
|
)
|
|
362
362
|
```
|
|
363
363
|
|
|
364
|
+
### Subscriptions and scheduled autopay (no SDK method)
|
|
365
|
+
|
|
366
|
+
The SDK signs the merchant-side recurring approval challenge
|
|
367
|
+
(`createDirectRequestPaymentRecurringChallenge` /
|
|
368
|
+
`create_direct_request_payment_recurring_challenge`), but there is **no SDK
|
|
369
|
+
method for subscription creation**. After you hand the buyer the recurring
|
|
370
|
+
challenge, the subscription itself is created over **raw HTTP** with the buyer's
|
|
371
|
+
Siglume bearer token:
|
|
372
|
+
|
|
373
|
+
```text
|
|
374
|
+
POST /v1/sdrp/direct-payments/subscriptions
|
|
375
|
+
{ merchant, amount_minor, currency, cadence: "monthly", challenge }
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
For scheduled autopay (`cadence: "daily"`), the buyer instead creates a scheduled
|
|
379
|
+
auto-pay authorization and hands you a `schedule_token`; your scheduler triggers
|
|
380
|
+
each occurrence with that token. Neither of these calls is wrapped by
|
|
381
|
+
`DirectRequestPaymentClient` today — the SDK's recurring surface is the challenge
|
|
382
|
+
signer and verifier only.
|
|
383
|
+
|
|
364
384
|
## 4. Fulfill from Webhook
|
|
365
385
|
|
|
366
386
|
Use the webhook as the durable signal, not just the browser return path.
|
|
@@ -425,6 +445,13 @@ if verified["event"]["type"] == "direct_payment.confirmed":
|
|
|
425
445
|
- `EXTERNAL_402_MERCHANT_BILLING_PAST_DUE` or
|
|
426
446
|
`EXTERNAL_402_MERCHANT_BILLING_SUSPENDED`: merchant billing must be fixed
|
|
427
447
|
before new payments can be accepted.
|
|
448
|
+
- `METERED_SETTLEMENT_PAST_DUE` (Micro / Nano only): a previous Micro / Nano
|
|
449
|
+
metered settlement for this buyer is unresolved, so new Micro / Nano usage in
|
|
450
|
+
the same fee band is paused until it settles. Siglume retries settlement
|
|
451
|
+
automatically every 6 hours, up to 28 attempts, before it requires manual
|
|
452
|
+
resolution. The provider's Micro / Nano revenue stays unsettled until the
|
|
453
|
+
settlement succeeds. This is a settlement-side state, not a per-request
|
|
454
|
+
challenge error.
|
|
428
455
|
|
|
429
456
|
## Go-Live Checklist
|
|
430
457
|
|