@siglume/direct-request-payment 0.4.20 → 0.4.22

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.
@@ -11,7 +11,43 @@ The SDK supplies the readiness check, route files, webhook verification, payment
11
11
  classification, and the order-store adapter contract. Your app supplies the
12
12
  real order lookup and fulfillment writes.
13
13
 
14
- ## 0. Readiness first
14
+ ## 0. Run the sandbox first
15
+
16
+ Do this before touching live Siglume credentials. The local sandbox is a tiny
17
+ Siglume-compatible API server bundled with the SDK. It creates fake checkout
18
+ sessions, signs webhooks with your sandbox secret, records delivery status, and
19
+ never charges a wallet.
20
+
21
+ In one terminal, point it at your product's local webhook route:
22
+
23
+ ```bash
24
+ npx siglume-sdrp sandbox \
25
+ --origin http://localhost:3000 \
26
+ --webhook-url http://localhost:3000/payments/webhooks/siglume
27
+ ```
28
+
29
+ Use the values it prints in your product `.env`:
30
+
31
+ ```bash
32
+ SIGLUME_ENV=sandbox
33
+ SIGLUME_API_BASE=http://127.0.0.1:8787/v1
34
+ SIGLUME_MERCHANT_AUTH_TOKEN=sandbox_merchant_token
35
+ SIGLUME_DIRECT_PAYMENT_MERCHANT=sandbox_merchant
36
+ SHOP_PUBLIC_ORIGIN=http://localhost:3000
37
+ SHOP_WEBHOOK_URL=http://localhost:3000/payments/webhooks/siglume
38
+ SIGLUME_WEBHOOK_SECRET=whsec_sandbox_local
39
+ ```
40
+
41
+ Then run:
42
+
43
+ ```bash
44
+ npx siglume-check readiness --sandbox
45
+ ```
46
+
47
+ The sandbox readiness check proves your local server can receive a signed
48
+ `direct_payment.confirmed` delivery before you use live credentials.
49
+
50
+ ## 1. Live readiness
15
51
 
16
52
  Install the SDK in your product.
17
53
 
@@ -64,7 +100,7 @@ npx siglume-check readiness --no-api --json
64
100
  human web checkout path, run readiness without `--no-api` and fix every FAIL
65
101
  item.
66
102
 
67
- ## 1. Copy integration files into your product
103
+ ## 2. Copy integration files into your product
68
104
 
69
105
  For Express:
70
106
 
@@ -81,7 +117,7 @@ siglume-sdrp init fastapi --target app/siglume
81
117
  These commands copy framework-specific route files into your codebase. The
82
118
  generated files are intentionally small and are meant to be edited.
83
119
 
84
- ## 2. Mount the routes
120
+ ## 3. Mount the routes
85
121
 
86
122
  Express:
87
123
 
@@ -125,7 +161,7 @@ app.include_router(
125
161
  )
126
162
  ```
127
163
 
128
- ## 3. Replace the order-store example
164
+ ## 4. Adapter responsibilities
129
165
 
130
166
  Replace the example store with your product's order database. The adapter must:
131
167
 
@@ -146,7 +182,51 @@ Micro / Nano, checkout returns `METERED_INTEGRATION_REQUIRED` until you set
146
182
  fulfilled-but-unsettled state, settlement reconciliation, past-due handling, and
147
183
  terminal write-off handling.
148
184
 
149
- ## 4. Start checkout from your frontend
185
+ ## 5. Use a real database adapter
186
+
187
+ The copied files include durable database adapters. Use these before opening
188
+ checkout to users; the `*.example.*` stores are only for reading the interface.
189
+
190
+ Express:
191
+
192
+ ```ts
193
+ import {
194
+ createPrismaSiglumeOrderStore,
195
+ createTypeOrmSiglumeOrderStore,
196
+ createSequelizeSiglumeOrderStore,
197
+ createDrizzleSiglumeOrderStore,
198
+ } from "./siglume/siglume-order-store.sql.js";
199
+
200
+ const order_store = createPrismaSiglumeOrderStore(prisma, {
201
+ dialect: "postgres",
202
+ orders_table: "orders",
203
+ order_id_column: "id",
204
+ amount_minor_column: "amount_minor",
205
+ currency_column: "currency",
206
+ });
207
+ ```
208
+
209
+ FastAPI:
210
+
211
+ ```py
212
+ from sqlalchemy.orm import sessionmaker
213
+ from .siglume.siglume_order_store_sqlalchemy import (
214
+ SQLAlchemySiglumeOrderStore,
215
+ create_sqlalchemy_engine,
216
+ create_sqlalchemy_siglume_schema,
217
+ )
218
+
219
+ engine = create_sqlalchemy_engine(os.environ["DATABASE_URL"])
220
+ create_sqlalchemy_siglume_schema(engine)
221
+ SessionLocal = sessionmaker(engine, future=True)
222
+ order_store = SQLAlchemySiglumeOrderStore(SessionLocal)
223
+ ```
224
+
225
+ The adapters persist one checkout attempt per order, reuse the checkout URL on
226
+ retries, record webhook event ids only after the order update/review write
227
+ succeeds, and keep duplicate deliveries from double-fulfilling an order.
228
+
229
+ ## 6. Start checkout from your frontend
150
230
 
151
231
  Call your own server route:
152
232
 
@@ -158,16 +238,17 @@ curl -X POST https://api.your-product.example/payments/checkout/siglume/start \
158
238
 
159
239
  Redirect the shopper to the returned `checkout_url`.
160
240
 
161
- ## 5. Done means
241
+ ## 7. Done means
162
242
 
163
243
  Your product is integrated when:
164
244
 
165
- - `npx siglume-check readiness` passes,
245
+ - `npx siglume-check readiness --sandbox` passes against your local product,
246
+ - `npx siglume-check readiness` passes against live Siglume credentials,
166
247
  - your product has mounted checkout and webhook routes,
167
- - your order database stores one active checkout attempt and `challenge_hash` for the order,
248
+ - your order database uses the SQL/ORM adapter or an equivalent transactional store,
168
249
  - the signed webhook verifies against the raw body,
169
250
  - `standard_settled` marks the order paid once,
170
- - duplicate webhook deliveries do not double-fulfill the order.
251
+ - a failed webhook handler is retried and duplicate webhook deliveries do not double-fulfill the order.
171
252
 
172
253
  For Micro / Nano revenue reconciliation, read
173
254
  [Payment lifecycle](./payment-lifecycle.md) and
@@ -0,0 +1,60 @@
1
+ # SDRP Sandbox
2
+
3
+ Use the SDK sandbox before live Siglume credentials. It is a local
4
+ Siglume-compatible API server for product integration testing. It creates fake
5
+ checkout sessions, signs `direct_payment.confirmed` webhooks, records delivery
6
+ status, and never charges a wallet.
7
+
8
+ Start your product locally first, then run:
9
+
10
+ ```bash
11
+ npx siglume-sdrp sandbox \
12
+ --origin http://localhost:3000 \
13
+ --webhook-url http://localhost:3000/payments/webhooks/siglume
14
+ ```
15
+
16
+ Set the printed environment variables in your product:
17
+
18
+ ```bash
19
+ SIGLUME_ENV=sandbox
20
+ SIGLUME_API_BASE=http://127.0.0.1:8787/v1
21
+ SIGLUME_MERCHANT_AUTH_TOKEN=sandbox_merchant_token
22
+ SIGLUME_DIRECT_PAYMENT_MERCHANT=sandbox_merchant
23
+ SHOP_PUBLIC_ORIGIN=http://localhost:3000
24
+ SHOP_WEBHOOK_URL=http://localhost:3000/payments/webhooks/siglume
25
+ SIGLUME_WEBHOOK_SECRET=whsec_sandbox_local
26
+ ```
27
+
28
+ Then verify the integration:
29
+
30
+ ```bash
31
+ npx siglume-check readiness --sandbox
32
+ ```
33
+
34
+ Create a checkout through your own product route:
35
+
36
+ ```bash
37
+ curl -X POST http://localhost:3000/payments/checkout/siglume/start \
38
+ -H "content-type: application/json" \
39
+ -d "{\"order_id\":\"order_123\"}"
40
+ ```
41
+
42
+ Open the returned `checkout_url` and click the sandbox confirm button. Your
43
+ product should receive a signed webhook and mark the Standard order paid once.
44
+
45
+ Sandbox Micro / Nano behavior follows the same public classifications:
46
+
47
+ - JPY 501+ / USD 3.01+ returns `standard_settled`.
48
+ - JPY 50-500 / USD 0.31-3.00 returns `metered_usage_accepted` with weekly Micro settlement fields.
49
+ - JPY 1-49 / USD 0.01-0.30 returns `metered_usage_accepted` with monthly Nano settlement fields.
50
+
51
+ The generated route defaults to Standard-only, so Micro / Nano checkout returns
52
+ `METERED_INTEGRATION_REQUIRED` until you explicitly enable metered handling.
53
+
54
+ Before live launch:
55
+
56
+ - run `npx siglume-check readiness --sandbox` against the local product,
57
+ - run the same checkout path and confirm a sandbox webhook,
58
+ - switch to live `SIGLUME_MERCHANT_AUTH_TOKEN`, `SIGLUME_DIRECT_PAYMENT_MERCHANT`, `SHOP_PUBLIC_ORIGIN`, `SHOP_WEBHOOK_URL`, and `SIGLUME_WEBHOOK_SECRET`,
59
+ - run `npx siglume-check readiness` without `--sandbox`,
60
+ - confirm the live webhook subscription and signing secret are for the live product URL.
@@ -11,12 +11,15 @@ Hosted Checkout is enabled account by account during beta. Check this before
11
11
  building a human web checkout:
12
12
 
13
13
  ```bash
14
+ npx siglume-check readiness --sandbox
14
15
  npx siglume-check readiness
15
16
  ```
16
17
 
17
- The command validates local configuration, reads the merchant account, checks
18
- the active billing mandate, confirms the webhook subscription, creates one
19
- unpaid expiring checkout session, and queues a signed webhook test delivery.
18
+ Run `--sandbox` against the local SDK sandbox first. Then run the same command
19
+ without `--sandbox` against live credentials. The command validates local
20
+ configuration, reads the merchant account, checks the active billing mandate,
21
+ confirms the webhook subscription, creates one unpaid expiring checkout session,
22
+ and queues a signed webhook test delivery.
20
23
 
21
24
  - The merchant account exists.
22
25
  - The merchant billing mandate is active.
@@ -31,6 +34,11 @@ unpaid expiring checkout session, and queues a signed webhook test delivery.
31
34
  `--no-api` is only for local config smoke tests. `--no-probe` is a partial API
32
35
  check and does not report readiness as ready.
33
36
 
37
+ If sandbox readiness fails, make sure `SIGLUME_ENV=sandbox`,
38
+ `SIGLUME_API_BASE=http://127.0.0.1:8787/v1`, `SHOP_PUBLIC_ORIGIN`, and
39
+ `SHOP_WEBHOOK_URL` all point to your local product, and that
40
+ `siglume-sdrp sandbox --webhook-url ...` is still running.
41
+
34
42
  If `createCheckoutSession(...)` or `getCheckoutSession(...)` raises
35
43
  `HostedCheckoutNotAvailableError`, do not show the raw 404/409 to the buyer.
36
44
  Stop the human checkout flow and contact Siglume support or your Siglume account
@@ -5,5 +5,5 @@ requires-python = ">=3.11"
5
5
  dependencies = [
6
6
  "Flask>=3.0,<4",
7
7
  "python-dotenv>=1.0,<2",
8
- "siglume-direct-request-payment>=0.4.20,<0.5",
8
+ "siglume-direct-request-payment>=0.4.22,<0.5",
9
9
  ]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@siglume/direct-request-payment",
3
- "version": "0.4.20",
3
+ "version": "0.4.22",
4
4
  "description": "SDK for the Siglume Direct Request Payment SDRP payment protocol",
5
5
  "keywords": [
6
6
  "siglume",
@@ -79,9 +79,17 @@
79
79
  "pack:check": "npm pack --json"
80
80
  },
81
81
  "devDependencies": {
82
+ "@types/express": "^5.0.6",
82
83
  "@types/node": "^20.16.5",
84
+ "@types/sql.js": "^1.4.11",
85
+ "esbuild": "^0.28.1",
86
+ "express": "^5.2.1",
87
+ "sql.js": "^1.14.1",
83
88
  "tsup": "^8.3.0",
84
89
  "typescript": "^5.6.3",
85
- "vitest": "^2.1.8"
90
+ "vitest": "^4.1.9"
91
+ },
92
+ "overrides": {
93
+ "esbuild": "^0.28.1"
86
94
  }
87
95
  }
@@ -10,7 +10,16 @@ import {
10
10
  createSiglumeSdrpWebhookHandler,
11
11
  type SiglumeSdrpRouterOptions,
12
12
  } from "./siglume/siglume-sdrp-routes.js";
13
- import { siglumeOrderStore } from "./siglume/siglume-order-store.example.js";
13
+ import { createPrismaSiglumeOrderStore } from "./siglume/siglume-order-store.sql.js";
14
+ import { prisma } from "../db/prisma.js";
15
+
16
+ const siglumeOrderStore = createPrismaSiglumeOrderStore(prisma, {
17
+ dialect: "postgres",
18
+ orders_table: "orders",
19
+ order_id_column: "id",
20
+ amount_minor_column: "amount_minor",
21
+ currency_column: "currency",
22
+ });
14
23
 
15
24
  const siglumeOptions: SiglumeSdrpRouterOptions = {
16
25
  merchant: process.env.SIGLUME_DIRECT_PAYMENT_MERCHANT!,
@@ -31,7 +40,12 @@ app.use(express.json());
31
40
  app.use("/payments", createSiglumeSdrpCheckoutRouter(siglumeOptions));
32
41
  ```
33
42
 
34
- Replace `siglume-order-store.example.ts` with your real order database adapter.
43
+ Use `siglume-order-store.sql.ts` for a durable database-backed adapter. It
44
+ supports Prisma, TypeORM, Sequelize, Drizzle, and any driver that can implement
45
+ the small `SiglumeSqlExecutor` interface. Run
46
+ `createSiglumeSdrpSqlSchema({ dialect: "postgres" })` once in a migration or
47
+ translate the returned SQL into your migration tool.
48
+
35
49
  Keep `processWebhookEventOnce()` transactional: record the webhook event as
36
50
  processed only after the order update or review write succeeds. The generated
37
51
  route defaults to Standard-only. Enable `allow_metered_payments` only after you