@siglume/direct-request-payment 0.4.16 → 0.4.18

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 CHANGED
@@ -1,5 +1,42 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.4.18 - 2026-06-19
4
+
5
+ Developer-onboarding cleanup for the v0.4.17 public review.
6
+
7
+ - Added a scoped 10-minute first-test guide for one Standard Payment Hosted
8
+ Checkout flow, with explicit prerequisites and non-goals.
9
+ - Added payment lifecycle and troubleshooting docs covering Hosted Checkout
10
+ readiness, webhook failure handling, retries, support references, and refund
11
+ escalation boundaries.
12
+ - Added README glossary and use-case fit tables so merchant / provider /
13
+ publisher / payee wording and 10-minute claims are less ambiguous.
14
+ - Added minimal Hosted Checkout TypeScript and Python starter directories with
15
+ `.env.example`, seeded test order, checkout start route, and webhook handler.
16
+ - Replaced "Stripe Checkout equivalent" wording with Siglume wallet hosted
17
+ checkout wording in public docs and SDK comments.
18
+ - Exported Python `TypedDict` response names for Hosted Checkout, Micro / Nano
19
+ summaries, settlement batches, webhook verification, and confirmation
20
+ classification.
21
+ - Marked the existing Express checkout example as demo-only and not
22
+ production-safe.
23
+
24
+ ## 0.4.17 - 2026-06-19
25
+
26
+ Public-surface cleanup for the v0.4.15 external review.
27
+
28
+ - Classified signed `direct_payment.confirmed` webhooks with unsupported
29
+ `data.mode` as `unknown` with `unsupported_confirmation_mode`, instead of
30
+ failing raw webhook parsing.
31
+ - Added stricter TypeScript settlement/open-period summary types and public
32
+ webhook amount/threshold fields.
33
+ - Rejected unsafe API base URLs and webhook callback URLs in both TypeScript
34
+ and Python helpers.
35
+ - Added release workflow checks that tag names match package versions before
36
+ publishing.
37
+ - Aligned README and docs wording around the buyer / provider / token / pricing
38
+ band exposure scope and fixed JPY / USD threshold wording.
39
+
3
40
  ## 0.4.16 - 2026-06-19
4
41
 
5
42
  SDRP Micro / Nano terminal-risk and idempotency hardening release.
package/README.md CHANGED
@@ -24,7 +24,7 @@ reflects this 402 lineage.
24
24
  Use this package when an external EC site, booking service, membership service,
25
25
  or paid API wants to accept Siglume wallet payments without taking custody of
26
26
  customer funds. The SDK creates and verifies one-time and recurring wallet
27
- payments; it does not hold customer funds or wallets.
27
+ payment authorizations; it does not hold customer funds or wallets.
28
28
 
29
29
  **Current public beta scope.** SDRP currently settles JPYC / USDC on **Polygon
30
30
  PoS only**. The public SDK does not expose chain selection, cross-chain payment,
@@ -56,7 +56,7 @@ buyer**.
56
56
  redirect them to the returned `checkout_url`. They sign into Siglume (passkey
57
57
  or email code — the login *is* the wallet), review the amount, approve once,
58
58
  and pay from their own wallet, then return to your `success_url`. This is the
59
- Stripe-Checkout-equivalent path.
59
+ Siglume wallet hosted checkout path.
60
60
 
61
61
  2. **AI agent / agent-to-agent (AtoA) → direct API / tools.** An autonomous
62
62
  buyer agent pays through `DirectRequestPaymentClient` (your app holds the
@@ -78,6 +78,39 @@ Honest framing: the part that integrates quickly is the **merchant plumbing**
78
78
  shopper to have — or create — a Siglume wallet and pay from it; it is not a
79
79
  card-style "instant" checkout for first-time buyers.
80
80
 
81
+ ## Fast Path
82
+
83
+ If your merchant account, Hosted Checkout enablement, billing mandate, HTTPS
84
+ webhook URL, and buyer test wallet are already ready, use
85
+ [10-Minute First Test Payment](./docs/quickstart-10-minutes.md) to connect one
86
+ Standard Payment test. That page is intentionally scoped to a first test
87
+ payment, not a production launch.
88
+
89
+ Before implementation, confirm Hosted Checkout readiness in
90
+ [Troubleshooting](./docs/troubleshooting.md#hosted-checkout-readiness). For
91
+ state handling, read [Payment lifecycle](./docs/payment-lifecycle.md) before
92
+ fulfilling orders.
93
+
94
+ ## Who Is Who
95
+
96
+ | Term | Meaning for public integrations |
97
+ | --- | --- |
98
+ | Buyer | The Siglume wallet user who pays. The merchant SDK does not log this user in. |
99
+ | Merchant | The external product or store that starts checkout, owns the order, and verifies webhooks. |
100
+ | Provider | The revenue recipient in Micro / Nano statements. In a simple EC integration this is usually the same business as the merchant. |
101
+ | Publisher / listing owner | Marketplace-facing owner of a listing or capability. Most Hosted Checkout merchants do not need to handle this term directly. |
102
+ | Payee | Internal settlement-grouping language. Public integration guides avoid this term unless a statement API field includes it. |
103
+
104
+ ## Use-Case Fit
105
+
106
+ | Use case | Recommended path | 10-minute demo? | Production work still required |
107
+ | --- | --- | --- | --- |
108
+ | EC one-time Standard payment | Hosted Checkout | Yes, if prerequisites are ready | Durable order DB, webhook dedupe, refund/support process, monitoring |
109
+ | Game consumables | Hosted Checkout or agent/API | Conditional | Idempotent entitlement grants, disconnect recovery, Micro / Nano unsettled-risk handling |
110
+ | Paid API / AtoA | Direct API or Siglume marketplace tool | Conditional | Request idempotency, buyer auth context, reconciliation |
111
+ | SaaS subscription | Recurring challenge plus raw API | No | Renewal, cancellation, failed renewal, plan-change lifecycle |
112
+ | Scheduled autopay | Recurring challenge plus schedule token | No | Scheduler, token custody, budget failure handling |
113
+
81
114
  ## Hosted Checkout (Human Web Shoppers)
82
115
 
83
116
  **Beta / server rollout:** Hosted Checkout is rolling out account by account.
@@ -86,6 +119,8 @@ case `createCheckoutSession(...)` / `getCheckoutSession(...)` raises
86
119
  `HostedCheckoutNotAvailableError` instead of exposing the raw rollout 404/409.
87
120
  Keep the signed `direct_payment.confirmed` webhook as the durable signal, and
88
121
  inspect its settlement machine fields before marking any order paid.
122
+ Check readiness before you build the flow; see
123
+ [Hosted Checkout readiness](./docs/troubleshooting.md#hosted-checkout-readiness).
89
124
 
90
125
  Hosted Checkout is a Siglume-hosted page that turns a "Pay with Siglume" button
91
126
  into a completed wallet payment, then returns the shopper to your store. It
@@ -199,11 +234,11 @@ setup, and after that the applied fee and the settlement timing follow the
199
234
  - **Standard Payment** — most payments. Your selected plan's percentage fee,
200
235
  settled on-chain immediately after each payment confirms.
201
236
  - **Micro Payment** — small payments, applied automatically by amount. A flat
202
- per-SDRP-Tx protocol fee, settled weekly or earlier when the buyer/payee
203
- batch reaches JPY 10,000 / USD 100.00.
237
+ per-SDRP-Tx protocol fee, settled weekly or earlier when the same buyer /
238
+ provider / token / pricing band reaches JPY 10,000 / USD 100.00.
204
239
  - **Nano Payment** — very small payments, applied automatically by amount. A
205
- flat per-SDRP-Tx protocol fee, settled monthly or earlier when the buyer/payee
206
- batch reaches JPY 10,000 / USD 100.00.
240
+ flat per-SDRP-Tx protocol fee, settled monthly or earlier when the same buyer
241
+ / provider / token / pricing band reaches JPY 10,000 / USD 100.00.
207
242
 
208
243
  Here, `Tx` means one accepted SDRP payment, not the later on-chain settlement
209
244
  transaction. Micro / Nano settlement batches are aggregated on-chain after the
@@ -277,16 +312,17 @@ Pricing has one structure: choose a Standard Payment plan, then Siglume applies
277
312
  the fee for each payment by amount. Micro / Nano are automatic amount bands, not
278
313
  extra setup choices.
279
314
 
280
- Both launch settlement currencies are first-class: JPY settled in JPYC, and USD
281
- settled in USDC. A merchant settles in one currency, chosen at onboarding. The
282
- settlement fee percentage is identical in both currencies; only the flat
283
- amounts differ.
315
+ Both launch settlement currencies are first-class where enabled: JPY settled in
316
+ JPYC, and USD settled in USDC. Some accounts may require agreed USD/USDC terms
317
+ before USD is enabled. A merchant settles in one currency, chosen at
318
+ onboarding. The settlement fee percentage is identical in both currencies; only
319
+ the flat amounts differ.
284
320
 
285
321
  | Public one-time payment amount | Applied automatically | What you select | Fee | Settlement |
286
322
  | --- | --- | --- | --- | --- |
287
323
  | JPY 501+ / USD 3.01+ | Standard Payment | Select one Standard plan: Launch, Starter, Growth, or Pro | Launch: JPY 0 / USD 0 monthly, 1.8%; Starter: JPY 980 / USD 6 monthly, 1.0%; Growth: JPY 2,980 / USD 18 monthly, 0.7%; Pro: JPY 9,800 / USD 60 monthly, 0.5%. Minimum JPY 30 / USD 0.20 per payment. | Settled on-chain immediately after the payment confirms |
288
- | JPY 50-500 / USD 0.31-3.00 | Micro Payment | Applied automatically by amount | JPY 2 / USD 0.01 per SDRP Tx | Weekly settlement, or earlier at JPY 10,000 / USD 100.00 - see [Settlement schedule](./docs/pricing.md#settlement-schedule) |
289
- | JPY 1-49 / USD 0.01-0.30 | Nano Payment | Applied automatically by amount | JPY 0.2 / USD 0.001 per SDRP Tx | Monthly settlement, or earlier at JPY 10,000 / USD 100.00 - see [Settlement schedule](./docs/pricing.md#settlement-schedule) |
324
+ | JPY 50-500 / USD 0.31-3.00 | Micro Payment | Applied automatically by amount | JPY 2 / USD 0.01 per SDRP Tx | Closes weekly, or earlier when provider gross reaches JPY 10,000 / USD 100.00. See [Settlement schedule](./docs/pricing.md#settlement-schedule). |
325
+ | JPY 1-49 / USD 0.01-0.30 | Nano Payment | Applied automatically by amount | JPY 0.2 / USD 0.001 per SDRP Tx | Closes monthly, or earlier when provider gross reaches JPY 10,000 / USD 100.00. See [Settlement schedule](./docs/pricing.md#settlement-schedule). |
290
326
 
291
327
  In this table, `Tx` means one accepted SDRP payment, not an on-chain settlement
292
328
  transaction.
@@ -640,7 +676,9 @@ an order paid from the event type alone.
640
676
  - Do not treat Direct Request Payment as stored value, prepaid points, escrow, or
641
677
  a platform balance.
642
678
 
643
- Read [docs/security.md](./docs/security.md) before going live.
679
+ Read [docs/security.md](./docs/security.md) before going live. Use
680
+ [docs/troubleshooting.md](./docs/troubleshooting.md) for operational error
681
+ handling and support escalation.
644
682
 
645
683
  ## Go-Live Checklist
646
684
 
@@ -669,12 +707,17 @@ Read [docs/security.md](./docs/security.md) before going live.
669
707
  ## Documentation
670
708
 
671
709
  - [Merchant quickstart](./docs/merchant-quickstart.md)
710
+ - [10-minute first test payment](./docs/quickstart-10-minutes.md)
711
+ - [Payment lifecycle](./docs/payment-lifecycle.md)
712
+ - [Troubleshooting](./docs/troubleshooting.md)
672
713
  - [API reference](./docs/api-reference.md)
673
714
  - [Pricing](./docs/pricing.md)
674
715
  - [Micro / Nano statements and notices](./docs/metered-statements.md)
675
716
  - [Security guide](./docs/security.md)
676
717
  - [Merchant setup example](./examples/setup-merchant.ts)
677
718
  - [Express checkout example](./examples/express-checkout.ts)
719
+ - [Hosted Checkout TypeScript starter](./examples/hosted-checkout-typescript)
720
+ - [Hosted Checkout Python starter](./examples/hosted-checkout-python)
678
721
  - [Japanese launch announcement draft](./docs/announcement-ja.md)
679
722
  - [Changelog](./CHANGELOG.md)
680
723
 
package/dist/index.cjs CHANGED
@@ -83,7 +83,7 @@ var DIRECT_REQUEST_PAYMENT_RECEIPT_KIND = "sdrp_direct_payment";
83
83
  var DIRECT_REQUEST_PAYMENT_ALLOWANCE_RECEIPT_KIND = "sdrp_direct_payment_allowance";
84
84
  var DIRECT_REQUEST_PAYMENT_REFERENCE_TYPE = "sdrp_direct_payment_requirement";
85
85
  var DEFAULT_WEBHOOK_TOLERANCE_SECONDS = 300;
86
- var DIRECT_REQUEST_PAYMENT_SDK_VERSION = "0.4.16";
86
+ var DIRECT_REQUEST_PAYMENT_SDK_VERSION = "0.4.18";
87
87
  var DIRECT_REQUEST_PAYMENT_STANDARD_SETTLED_STATUS = "settled";
88
88
  var DIRECT_REQUEST_PAYMENT_METERED_ACCEPTED_STATUS = "pending_settlement";
89
89
  var DIRECT_REQUEST_PAYMENT_STANDARD_FINALITY = "per_payment_onchain";
@@ -126,7 +126,7 @@ var SiglumeWebhookPayloadError = class extends SiglumeDirectRequestPaymentError
126
126
  }
127
127
  };
128
128
  var DirectRequestPaymentClient = class {
129
- auth_token;
129
+ #authToken;
130
130
  base_url;
131
131
  timeout_ms;
132
132
  user_agent;
@@ -142,8 +142,8 @@ var DirectRequestPaymentClient = class {
142
142
  if (!fetchImpl) {
143
143
  throw new SiglumeDirectRequestPaymentError("A fetch implementation is required in this runtime.");
144
144
  }
145
- this.auth_token = authToken;
146
- this.base_url = (options.base_url ?? envValue("SIGLUME_API_BASE") ?? DEFAULT_SIGLUME_API_BASE).replace(/\/+$/, "");
145
+ this.#authToken = authToken;
146
+ this.base_url = normalizeApiBaseUrl(options.base_url ?? envValue("SIGLUME_API_BASE") ?? DEFAULT_SIGLUME_API_BASE);
147
147
  this.timeout_ms = Math.max(1, Math.trunc(options.timeout_ms ?? 15e3));
148
148
  this.user_agent = options.user_agent ?? `@siglume/direct-request-payment/${DIRECT_REQUEST_PAYMENT_SDK_VERSION}`;
149
149
  this.fetch_impl = fetchImpl;
@@ -246,7 +246,7 @@ var DirectRequestPaymentClient = class {
246
246
  try {
247
247
  const headers = {
248
248
  "Accept": "application/json",
249
- "Authorization": `Bearer ${this.auth_token}`,
249
+ "Authorization": `Bearer ${this.#authToken}`,
250
250
  "User-Agent": this.user_agent
251
251
  };
252
252
  let body;
@@ -278,7 +278,7 @@ var DirectRequestPaymentClient = class {
278
278
  }
279
279
  };
280
280
  var DirectRequestPaymentMerchantClient = class {
281
- auth_token;
281
+ #authToken;
282
282
  base_url;
283
283
  timeout_ms;
284
284
  user_agent;
@@ -294,8 +294,8 @@ var DirectRequestPaymentMerchantClient = class {
294
294
  if (!fetchImpl) {
295
295
  throw new SiglumeDirectRequestPaymentError("A fetch implementation is required in this runtime.");
296
296
  }
297
- this.auth_token = authToken;
298
- this.base_url = (options.base_url ?? envValue("SIGLUME_API_BASE") ?? DEFAULT_SIGLUME_API_BASE).replace(/\/+$/, "");
297
+ this.#authToken = authToken;
298
+ this.base_url = normalizeApiBaseUrl(options.base_url ?? envValue("SIGLUME_API_BASE") ?? DEFAULT_SIGLUME_API_BASE);
299
299
  this.timeout_ms = Math.max(1, Math.trunc(options.timeout_ms ?? 15e3));
300
300
  this.user_agent = options.user_agent ?? `@siglume/direct-request-payment/${DIRECT_REQUEST_PAYMENT_SDK_VERSION}`;
301
301
  this.fetch_impl = fetchImpl;
@@ -313,7 +313,7 @@ var DirectRequestPaymentMerchantClient = class {
313
313
  payload.allowed_currencies = normalizeAllowedCurrencies(input.allowed_currencies);
314
314
  }
315
315
  if (input.webhook_callback_url !== void 0) {
316
- payload.webhook_callback_url = requireNonEmpty(input.webhook_callback_url, "webhook_callback_url");
316
+ payload.webhook_callback_url = normalizeHttpsUrl(input.webhook_callback_url, "webhook_callback_url");
317
317
  }
318
318
  if (input.billing_mandate_cap_minor !== void 0) {
319
319
  payload.billing_mandate_cap_minor = positiveInteger(input.billing_mandate_cap_minor, "billing_mandate_cap_minor");
@@ -327,8 +327,8 @@ var DirectRequestPaymentMerchantClient = class {
327
327
  return this.request("POST", "/sdrp/direct-payments/merchants", payload);
328
328
  }
329
329
  /**
330
- * Create a Hosted Checkout session (Stripe-Checkout-equivalent for human web
331
- * shoppers). Siglume authors the challenge server-side, persists a single-use
330
+ * Create a Hosted Checkout session for human web shoppers. Siglume authors
331
+ * the challenge server-side, persists a single-use
332
332
  * expiring session, and returns a `checkout_url`. Redirect the shopper there;
333
333
  * they log into Siglume, approve, and pay from their own wallet, then return
334
334
  * to your `success_url`. Fulfill on the `direct_payment.confirmed` webhook
@@ -393,7 +393,7 @@ var DirectRequestPaymentMerchantClient = class {
393
393
  }
394
394
  async createWebhookSubscription(input) {
395
395
  const payload = {
396
- callback_url: requireNonEmpty(input.callback_url, "callback_url"),
396
+ callback_url: normalizeHttpsUrl(input.callback_url, "callback_url"),
397
397
  event_types: input.event_types?.length ? input.event_types.map((eventType) => requireNonEmpty(eventType, "event_type")) : ["direct_payment.confirmed", "direct_payment.spent"]
398
398
  };
399
399
  if (input.description !== void 0) {
@@ -436,7 +436,7 @@ var DirectRequestPaymentMerchantClient = class {
436
436
  try {
437
437
  const headers = {
438
438
  "Accept": "application/json",
439
- "Authorization": `Bearer ${this.auth_token}`,
439
+ "Authorization": `Bearer ${this.#authToken}`,
440
440
  "User-Agent": this.user_agent
441
441
  };
442
442
  let body;
@@ -674,11 +674,6 @@ function parseDirectRequestPaymentWebhookEvent(payload) {
674
674
  occurred_at: requireNonEmpty(stringOrNull(event.occurred_at) ?? "", "webhook occurred_at"),
675
675
  data: { ...data }
676
676
  };
677
- if (parsed.type === "direct_payment.confirmed" && !DIRECT_REQUEST_PAYMENT_CONFIRMED_WEBHOOK_MODES.has(String(parsed.data.mode ?? ""))) {
678
- throw new SiglumeWebhookPayloadError(
679
- "direct_payment.confirmed webhook must carry a supported Direct Request Payment mode."
680
- );
681
- }
682
677
  return parsed;
683
678
  }
684
679
  function classifyDirectPaymentConfirmation(event) {
@@ -689,6 +684,7 @@ function classifyDirectPaymentConfirmation(event) {
689
684
  const settlementCadence = stringOrNull(data.settlement_cadence);
690
685
  const finality = stringOrNull(data.finality);
691
686
  const settlementStatus = stringOrNull(data.settlement_status);
687
+ const mode = stringOrNull(data.mode);
692
688
  if (event.type !== "direct_payment.confirmed") {
693
689
  return {
694
690
  kind: "unknown",
@@ -703,7 +699,21 @@ function classifyDirectPaymentConfirmation(event) {
703
699
  finality
704
700
  };
705
701
  }
706
- if (data.mode === "metered_settlement_batch") {
702
+ if (!DIRECT_REQUEST_PAYMENT_CONFIRMED_WEBHOOK_MODES.has(mode ?? "")) {
703
+ return {
704
+ kind: "unknown",
705
+ event,
706
+ data,
707
+ reason: "unsupported_confirmation_mode",
708
+ requirement_id: requirementId,
709
+ settlement_batch_id: stringOrNull(data.settlement_batch_id),
710
+ pricing_band: pricingBand,
711
+ settlement_cadence: settlementCadence,
712
+ settlement_status: settlementStatus,
713
+ finality
714
+ };
715
+ }
716
+ if (mode === "metered_settlement_batch") {
707
717
  const settlementBatchId = stringOrNull(data.settlement_batch_id);
708
718
  const chainReceiptId = stringOrNull(data.chain_receipt_id);
709
719
  const usageEventDigest = stringOrNull(data.usage_event_digest);
@@ -875,6 +885,38 @@ function normalizeAllowedCurrencies(value) {
875
885
  function defaultTokenForCurrency(currency) {
876
886
  return currency === "JPY" ? "JPYC" : "USDC";
877
887
  }
888
+ function normalizeApiBaseUrl(value) {
889
+ let url;
890
+ try {
891
+ url = new URL(requireNonEmpty(value, "base_url"));
892
+ } catch {
893
+ throw new SiglumeDirectRequestPaymentError("base_url must be an absolute URL such as https://siglume.com/v1.");
894
+ }
895
+ if (url.username || url.password) {
896
+ throw new SiglumeDirectRequestPaymentError("base_url must not include userinfo.");
897
+ }
898
+ if (!isAllowedCheckoutOriginScheme(url)) {
899
+ throw new SiglumeDirectRequestPaymentError(
900
+ "base_url must use https, except http is allowed for localhost, 127.0.0.1, or [::1]."
901
+ );
902
+ }
903
+ return url.toString().replace(/\/+$/, "");
904
+ }
905
+ function normalizeHttpsUrl(value, name) {
906
+ let url;
907
+ try {
908
+ url = new URL(requireNonEmpty(value, name));
909
+ } catch {
910
+ throw new SiglumeDirectRequestPaymentError(`${name} must be an absolute https URL.`);
911
+ }
912
+ if (url.username || url.password) {
913
+ throw new SiglumeDirectRequestPaymentError(`${name} must not include userinfo.`);
914
+ }
915
+ if (url.protocol !== "https:" || !url.hostname) {
916
+ throw new SiglumeDirectRequestPaymentError(`${name} must use https.`);
917
+ }
918
+ return url.toString();
919
+ }
878
920
  function normalizeOriginList(value) {
879
921
  if (!Array.isArray(value)) {
880
922
  throw new SiglumeDirectRequestPaymentError("checkout_allowed_origins must be an array of origin URLs.");