@bitpal/checkout 0.6.0 → 0.8.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/README.md +96 -5
- package/dist/index.cjs +561 -3
- package/dist/index.d.cts +392 -1
- package/dist/index.d.ts +392 -1
- package/dist/index.js +550 -2
- package/package.json +6 -3
package/README.md
CHANGED
|
@@ -63,10 +63,16 @@ shows the per-order deposit address + QR, and confirms the payment on-chain.
|
|
|
63
63
|
```ts
|
|
64
64
|
const { data: session } = await bitpal.checkout.createSession({
|
|
65
65
|
line_items: [
|
|
66
|
-
{ name: 'Pro Plan', amount: '29', currency: 'USDC' }, //
|
|
66
|
+
{ name: 'Pro Plan', amount: '29', currency: 'USDC' }, // `currency` = price denomination (USD via USDC)
|
|
67
|
+
],
|
|
68
|
+
// Payment options the buyer may choose — (chain, token) pairs. Mix tokens freely.
|
|
69
|
+
// `chain` accepts a short-name ('base' | 'arbitrum' | 'bnb' | 'tron' | 'solana') or a CAIP-2 id;
|
|
70
|
+
// it resolves to the right testnet/mainnet chain for your mode (test vs live key) automatically.
|
|
71
|
+
allowed_assets: [
|
|
72
|
+
{ chain: 'base', token: 'USDC' },
|
|
73
|
+
{ chain: 'tron', token: 'USDT' },
|
|
74
|
+
{ chain: 'solana', token: 'USDC' },
|
|
67
75
|
],
|
|
68
|
-
pay_chain: 'eip155:84532', // Base Sepolia (test mode). Live mode: 'eip155:8453' (Base mainnet).
|
|
69
|
-
// Or use allowed_pay_chains for a buyer-picked chain.
|
|
70
76
|
expires_in_seconds: 1800,
|
|
71
77
|
success_url: 'https://yourstore.com/thanks',
|
|
72
78
|
});
|
|
@@ -75,7 +81,13 @@ const { data: session } = await bitpal.checkout.createSession({
|
|
|
75
81
|
redirect(session.checkout_url!);
|
|
76
82
|
```
|
|
77
83
|
|
|
78
|
-
|
|
84
|
+
**Setting the payment options** (precedence, highest first):
|
|
85
|
+
|
|
86
|
+
- **`allowed_assets`** — `(chain, token)` cells. The standard, most explicit way; the buyer picks any listed pair (lets you mix tokens, e.g. USDC on Base + USDT on Tron).
|
|
87
|
+
- `allowed_pay_chains: string[]` — shorthand for "the line-item `currency` across these chains" (one token, many chains).
|
|
88
|
+
- `pay_chain: string` — a single fixed chain, no buyer choice.
|
|
89
|
+
|
|
90
|
+
`pay_chain` and `allowed_pay_chains` are mutually exclusive; `allowed_assets` takes precedence over both. Omit all three and it defaults to **one chain × the line-item currency**. `currency` on the line item is always the **price denomination** (what the amount is quoted in) — independent of which token the buyer pays with.
|
|
79
91
|
|
|
80
92
|
### Self-hosted flow: issue a deposit address yourself
|
|
81
93
|
|
|
@@ -89,7 +101,7 @@ const { data } = await bitpal.checkout.issueDepositAddress(session.id, {
|
|
|
89
101
|
session_token: session.session_token!, // from createSession
|
|
90
102
|
refundAddress: '0xBuyerWallet...', // VM-matched (EVM 0x… / Tron T… / Solana base58); committed, immutable after issuance
|
|
91
103
|
chain: 'eip155:84532', // match the session's chain (test: Base Sepolia / live: eip155:8453).
|
|
92
|
-
// only needed for multi-option (allowed_pay_chains) sessions
|
|
104
|
+
// only needed for multi-option (allowed_assets / allowed_pay_chains) sessions
|
|
93
105
|
token: 'USDC',
|
|
94
106
|
});
|
|
95
107
|
|
|
@@ -180,6 +192,85 @@ BitPal may still deliver the **same event more than once** within the window. De
|
|
|
180
192
|
is not signed, so it is forgeable). Persist the dedup key in the **same transaction** as your side
|
|
181
193
|
effect; handlers must be safe to run twice (UPSERT, not INSERT).
|
|
182
194
|
|
|
195
|
+
## x402 — charge per API call
|
|
196
|
+
|
|
197
|
+
A different lane from checkout: no page, no redirect, no deposit address. The caller pays with a
|
|
198
|
+
signed authorization and retries the request. Settles to the **same payout wallet as checkout**
|
|
199
|
+
(register one in the console first).
|
|
200
|
+
|
|
201
|
+
### Merchant side
|
|
202
|
+
|
|
203
|
+
```ts
|
|
204
|
+
import { x402 } from '@bitpal/checkout';
|
|
205
|
+
|
|
206
|
+
// $1.00 USDC per call
|
|
207
|
+
app.get('/report', x402({
|
|
208
|
+
apiKey: process.env.BITPAL_API_KEY, // bp_test_… or bp_live_…
|
|
209
|
+
payTo: '0xYourPayoutWallet',
|
|
210
|
+
network: 'base', // test key → 'base-sepolia'
|
|
211
|
+
amount: '1000000', // atomic (USDC, 6dp) — your gross; the fee comes out of it
|
|
212
|
+
}), (req, res) => {
|
|
213
|
+
res.json({ report: '…' }); // req.x402Payment has the txHash
|
|
214
|
+
});
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Unpaid requests get a `402` with the payment terms. Paid ones run `verify` → `settle` and reach your
|
|
218
|
+
handler with `X-PAYMENT-RESPONSE` set. The middleware also does what the API cannot do for you:
|
|
219
|
+
|
|
220
|
+
- **One payment unlocks one response.** `/settle` is idempotent, so replaying the same `X-PAYMENT`
|
|
221
|
+
keeps returning success — which would let one payment buy unlimited calls. The middleware records
|
|
222
|
+
redeemed authorizations and rejects reuse with `409`. Redemption is recorded only once your
|
|
223
|
+
response actually ships: if the handler throws, the caller can retry with the same header instead
|
|
224
|
+
of paying for nothing.
|
|
225
|
+
- **Only re-prompts for payment when the money definitely did not move.** `reverted`, `expired` and
|
|
226
|
+
`failed` get a fresh `402`. Everything else — settlement still in flight, an uncertain broadcast, a
|
|
227
|
+
timeout — answers `503` and asks for a retry with the *same* header. Handing back a `402` there
|
|
228
|
+
would make the caller re-sign and pay twice.
|
|
229
|
+
|
|
230
|
+
Not on Express? `X402Gate` is the framework-neutral core — give it the header and the resource URL,
|
|
231
|
+
it tells you whether to bill or serve. On a `settled` result, call `commit()` once you have delivered
|
|
232
|
+
the response, or `release()` if you could not.
|
|
233
|
+
|
|
234
|
+
**Two things to set for production:**
|
|
235
|
+
|
|
236
|
+
- `replayStore` — the default keeps redeemed payments in process memory, so a second instance does
|
|
237
|
+
not know what the first one served. Pass a shared store (Redis/DB) whose `claim` is an atomic
|
|
238
|
+
compare-and-set. The memory store also refuses new payments rather than evicting live entries once
|
|
239
|
+
it fills, so a busy single instance needs a real store too.
|
|
240
|
+
- `resource` — by default it is derived from the request's `Host` header, which the caller controls.
|
|
241
|
+
The payment binds to that string, so pass an explicit `resource` (or a function) to pin it.
|
|
242
|
+
|
|
243
|
+
### Payer side
|
|
244
|
+
|
|
245
|
+
The fee split needs two authorizations, which a stock x402 client does not know about.
|
|
246
|
+
`createX402Payment` reads the `402` and builds both. You supply the signer; the SDK has no crypto
|
|
247
|
+
dependency.
|
|
248
|
+
|
|
249
|
+
```ts
|
|
250
|
+
import { createX402Payment } from '@bitpal/checkout';
|
|
251
|
+
|
|
252
|
+
const res = await fetch(url);
|
|
253
|
+
if (res.status === 402) {
|
|
254
|
+
const { header } = await createX402Payment({
|
|
255
|
+
requirements: await res.json(),
|
|
256
|
+
from: account.address,
|
|
257
|
+
signTypedData: (req) => walletClient.signTypedData({ account, ...req }), // viem
|
|
258
|
+
});
|
|
259
|
+
const paid = await fetch(url, { headers: { 'X-PAYMENT': header } });
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Supported
|
|
264
|
+
|
|
265
|
+
| Network | Token | `network` |
|
|
266
|
+
|---|---|---|
|
|
267
|
+
| Base | USDC | `base` |
|
|
268
|
+
| Base Sepolia | USDC | `base-sepolia` |
|
|
269
|
+
|
|
270
|
+
EOA signers only — smart-contract wallets cannot sign EIP-3009 authorizations. Amounts are exact:
|
|
271
|
+
over- and underpayment are both rejected, and this lane has no refund path. Authorizations are valid
|
|
272
|
+
for 90–3600 seconds (the server's floor is 60s; the extra 30s absorbs clock skew and round trips).
|
|
273
|
+
|
|
183
274
|
## Config options
|
|
184
275
|
|
|
185
276
|
```ts
|