@siglume/direct-request-payment 0.4.15 → 0.4.17
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 +34 -0
- package/README.md +14 -9
- package/dist/index.cjs +59 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +73 -11
- package/dist/index.d.ts +73 -11
- package/dist/index.js +59 -17
- package/dist/index.js.map +1 -1
- package/docs/announcement-ja.md +1 -1
- package/docs/api-reference.md +19 -0
- package/docs/merchant-quickstart.md +11 -4
- package/docs/metered-statements.md +25 -6
- package/docs/pricing.md +31 -24
- package/examples/express-checkout.ts +3 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,39 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.4.17 - 2026-06-19
|
|
4
|
+
|
|
5
|
+
Public-surface cleanup for the v0.4.15 external review.
|
|
6
|
+
|
|
7
|
+
- Classified signed `direct_payment.confirmed` webhooks with unsupported
|
|
8
|
+
`data.mode` as `unknown` with `unsupported_confirmation_mode`, instead of
|
|
9
|
+
failing raw webhook parsing.
|
|
10
|
+
- Added stricter TypeScript settlement/open-period summary types and public
|
|
11
|
+
webhook amount/threshold fields.
|
|
12
|
+
- Rejected unsafe API base URLs and webhook callback URLs in both TypeScript
|
|
13
|
+
and Python helpers.
|
|
14
|
+
- Added release workflow checks that tag names match package versions before
|
|
15
|
+
publishing.
|
|
16
|
+
- Aligned README and docs wording around the buyer / provider / token / pricing
|
|
17
|
+
band exposure scope and fixed JPY / USD threshold wording.
|
|
18
|
+
|
|
19
|
+
## 0.4.16 - 2026-06-19
|
|
20
|
+
|
|
21
|
+
SDRP Micro / Nano terminal-risk and idempotency hardening release.
|
|
22
|
+
|
|
23
|
+
- Added public settlement batch fields for terminal provider accounting:
|
|
24
|
+
`terminal_provider_receivable_minor`,
|
|
25
|
+
`uncollectible_provider_receivable_minor`,
|
|
26
|
+
`written_off_provider_receivable_minor`, `terminal_status`,
|
|
27
|
+
`terminal_marked_at`, and `terminal_reason_code`.
|
|
28
|
+
- Documented operator terminal states `uncollectible` and `written_off` after
|
|
29
|
+
past-due manual review. These amounts are not settled, unsettled, or past-due
|
|
30
|
+
receivable.
|
|
31
|
+
- Documented merchant setup risk acceptance receipt
|
|
32
|
+
`merchant_account.metadata_jsonb.metered_risk_acceptance`.
|
|
33
|
+
- Documented fail-closed idempotency behavior:
|
|
34
|
+
`IDEMPOTENCY_KEY_REUSED_WITH_DIFFERENT_PAYLOAD` for reused keys with a
|
|
35
|
+
different metered input payload.
|
|
36
|
+
|
|
3
37
|
## 0.4.15 - 2026-06-19
|
|
4
38
|
|
|
5
39
|
Corrective SDRP Micro / Nano public-surface 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
|
-
|
|
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,
|
|
@@ -199,11 +199,11 @@ setup, and after that the applied fee and the settlement timing follow the
|
|
|
199
199
|
- **Standard Payment** — most payments. Your selected plan's percentage fee,
|
|
200
200
|
settled on-chain immediately after each payment confirms.
|
|
201
201
|
- **Micro Payment** — small payments, applied automatically by amount. A flat
|
|
202
|
-
per-SDRP-Tx protocol fee, settled weekly or earlier when the buyer/
|
|
203
|
-
|
|
202
|
+
per-SDRP-Tx protocol fee, settled weekly or earlier when the same buyer /
|
|
203
|
+
provider / token / pricing band reaches JPY 10,000 / USD 100.00.
|
|
204
204
|
- **Nano Payment** — very small payments, applied automatically by amount. A
|
|
205
|
-
flat per-SDRP-Tx protocol fee, settled monthly or earlier when the buyer
|
|
206
|
-
|
|
205
|
+
flat per-SDRP-Tx protocol fee, settled monthly or earlier when the same buyer
|
|
206
|
+
/ provider / token / pricing band reaches JPY 10,000 / USD 100.00.
|
|
207
207
|
|
|
208
208
|
Here, `Tx` means one accepted SDRP payment, not the later on-chain settlement
|
|
209
209
|
transaction. Micro / Nano settlement batches are aggregated on-chain after the
|
|
@@ -223,6 +223,10 @@ aggregated settlement model whenever they offer amounts in these bands. If a
|
|
|
223
223
|
product cannot fulfill before provider revenue is settled, keep the price in the
|
|
224
224
|
Standard band; in practice, do not offer JPY 500-and-under or USD 3-and-under
|
|
225
225
|
items for that product.
|
|
226
|
+
Self-service setup records this acceptance in
|
|
227
|
+
`merchant_account.metadata_jsonb.metered_risk_acceptance`, including
|
|
228
|
+
`terms_version`, `accepted_at`, `principal_user_id`, `receipt_id`, and fixed
|
|
229
|
+
market thresholds `JPY: 10000` / `USD: 10000`.
|
|
226
230
|
Micro / Nano budget checks reserve spending capacity only; they do not lock,
|
|
227
231
|
escrow, or guarantee the buyer's wallet balance, allowance, or settlement funds.
|
|
228
232
|
Sub-minor-unit Nano fees are accumulated with decimal precision, but they are
|
|
@@ -273,10 +277,11 @@ Pricing has one structure: choose a Standard Payment plan, then Siglume applies
|
|
|
273
277
|
the fee for each payment by amount. Micro / Nano are automatic amount bands, not
|
|
274
278
|
extra setup choices.
|
|
275
279
|
|
|
276
|
-
Both launch settlement currencies are first-class: JPY settled in
|
|
277
|
-
settled in USDC.
|
|
278
|
-
|
|
279
|
-
|
|
280
|
+
Both launch settlement currencies are first-class where enabled: JPY settled in
|
|
281
|
+
JPYC, and USD settled in USDC. Some accounts may require agreed USD/USDC terms
|
|
282
|
+
before USD is enabled. A merchant settles in one currency, chosen at
|
|
283
|
+
onboarding. The settlement fee percentage is identical in both currencies; only
|
|
284
|
+
the flat amounts differ.
|
|
280
285
|
|
|
281
286
|
| Public one-time payment amount | Applied automatically | What you select | Fee | Settlement |
|
|
282
287
|
| --- | --- | --- | --- | --- |
|
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.
|
|
86
|
+
var DIRECT_REQUEST_PAYMENT_SDK_VERSION = "0.4.17";
|
|
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
|
-
|
|
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
|
|
146
|
-
this.base_url = (options.base_url ?? envValue("SIGLUME_API_BASE") ?? DEFAULT_SIGLUME_API_BASE)
|
|
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
|
|
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
|
-
|
|
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
|
|
298
|
-
this.base_url = (options.base_url ?? envValue("SIGLUME_API_BASE") ?? DEFAULT_SIGLUME_API_BASE)
|
|
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 =
|
|
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");
|
|
@@ -393,7 +393,7 @@ var DirectRequestPaymentMerchantClient = class {
|
|
|
393
393
|
}
|
|
394
394
|
async createWebhookSubscription(input) {
|
|
395
395
|
const payload = {
|
|
396
|
-
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
|
|
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 (
|
|
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.");
|