@txnod/sdk 1.0.1
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/AGENTS.md +29 -0
- package/CHANGELOG.md +22 -0
- package/LICENSE +21 -0
- package/README.md +434 -0
- package/dist/_shared/index.d.ts +68 -0
- package/dist/client-sandbox.d.ts +396 -0
- package/dist/client-sandbox.d.ts.map +1 -0
- package/dist/client-sandbox.js +448 -0
- package/dist/client-sandbox.js.map +1 -0
- package/dist/client.d.ts +429 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +588 -0
- package/dist/client.js.map +1 -0
- package/dist/env.d.ts +29 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +44 -0
- package/dist/env.js.map +1 -0
- package/dist/errors.d.ts +1887 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +2107 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/internals/error-ctor-map.d.ts +11 -0
- package/dist/internals/error-ctor-map.d.ts.map +1 -0
- package/dist/internals/error-ctor-map.js +75 -0
- package/dist/internals/error-ctor-map.js.map +1 -0
- package/dist/internals/fetch-with-retry.d.ts +34 -0
- package/dist/internals/fetch-with-retry.d.ts.map +1 -0
- package/dist/internals/fetch-with-retry.js +233 -0
- package/dist/internals/fetch-with-retry.js.map +1 -0
- package/dist/internals/hmac.d.ts +2 -0
- package/dist/internals/hmac.d.ts.map +1 -0
- package/dist/internals/hmac.js +10 -0
- package/dist/internals/hmac.js.map +1 -0
- package/dist/internals/logger.d.ts +9 -0
- package/dist/internals/logger.d.ts.map +1 -0
- package/dist/internals/logger.js +16 -0
- package/dist/internals/logger.js.map +1 -0
- package/dist/internals/parse-problem-details.d.ts +3 -0
- package/dist/internals/parse-problem-details.d.ts.map +1 -0
- package/dist/internals/parse-problem-details.js +76 -0
- package/dist/internals/parse-problem-details.js.map +1 -0
- package/dist/internals/synthetic-details.d.ts +12 -0
- package/dist/internals/synthetic-details.d.ts.map +1 -0
- package/dist/internals/synthetic-details.js +19 -0
- package/dist/internals/synthetic-details.js.map +1 -0
- package/dist/verify/chains/bsc.d.ts +17 -0
- package/dist/verify/chains/bsc.d.ts.map +1 -0
- package/dist/verify/chains/bsc.js +15 -0
- package/dist/verify/chains/bsc.js.map +1 -0
- package/dist/verify/chains/btc.d.ts +22 -0
- package/dist/verify/chains/btc.d.ts.map +1 -0
- package/dist/verify/chains/btc.js +55 -0
- package/dist/verify/chains/btc.js.map +1 -0
- package/dist/verify/chains/cardano.d.ts +73 -0
- package/dist/verify/chains/cardano.d.ts.map +1 -0
- package/dist/verify/chains/cardano.js +175 -0
- package/dist/verify/chains/cardano.js.map +1 -0
- package/dist/verify/chains/evm.d.ts +21 -0
- package/dist/verify/chains/evm.d.ts.map +1 -0
- package/dist/verify/chains/evm.js +46 -0
- package/dist/verify/chains/evm.js.map +1 -0
- package/dist/verify/chains/polygon.d.ts +17 -0
- package/dist/verify/chains/polygon.d.ts.map +1 -0
- package/dist/verify/chains/polygon.js +15 -0
- package/dist/verify/chains/polygon.js.map +1 -0
- package/dist/verify/chains/secp256k1-bip32.d.ts +20 -0
- package/dist/verify/chains/secp256k1-bip32.d.ts.map +1 -0
- package/dist/verify/chains/secp256k1-bip32.js +88 -0
- package/dist/verify/chains/secp256k1-bip32.js.map +1 -0
- package/dist/verify/chains/ton-cell.d.ts +179 -0
- package/dist/verify/chains/ton-cell.d.ts.map +1 -0
- package/dist/verify/chains/ton-cell.js +614 -0
- package/dist/verify/chains/ton-cell.js.map +1 -0
- package/dist/verify/chains/ton.d.ts +84 -0
- package/dist/verify/chains/ton.d.ts.map +1 -0
- package/dist/verify/chains/ton.js +131 -0
- package/dist/verify/chains/ton.js.map +1 -0
- package/dist/verify/chains/tron.d.ts +21 -0
- package/dist/verify/chains/tron.d.ts.map +1 -0
- package/dist/verify/chains/tron.js +42 -0
- package/dist/verify/chains/tron.js.map +1 -0
- package/dist/verify/config.d.ts +41 -0
- package/dist/verify/config.d.ts.map +1 -0
- package/dist/verify/config.js +120 -0
- package/dist/verify/config.js.map +1 -0
- package/dist/verify/errors.d.ts +56 -0
- package/dist/verify/errors.d.ts.map +1 -0
- package/dist/verify/errors.js +58 -0
- package/dist/verify/errors.js.map +1 -0
- package/dist/verify/index.d.ts +119 -0
- package/dist/verify/index.d.ts.map +1 -0
- package/dist/verify/index.js +166 -0
- package/dist/verify/index.js.map +1 -0
- package/dist/verify/xpub-safety.d.ts +33 -0
- package/dist/verify/xpub-safety.d.ts.map +1 -0
- package/dist/verify/xpub-safety.js +54 -0
- package/dist/verify/xpub-safety.js.map +1 -0
- package/dist/verify-webhook-signature.d.ts +30 -0
- package/dist/verify-webhook-signature.d.ts.map +1 -0
- package/dist/verify-webhook-signature.js +84 -0
- package/dist/verify-webhook-signature.js.map +1 -0
- package/docs/00-getting-started.md +135 -0
- package/docs/01-authentication.md +114 -0
- package/docs/02-invoices.md +216 -0
- package/docs/03-rates-and-quotes.md +82 -0
- package/docs/04-webhooks.md +126 -0
- package/docs/05-errors.md +199 -0
- package/docs/05-sandbox.md +159 -0
- package/docs/06-idempotency.md +132 -0
- package/docs/examples/express-webhook-receiver.md +97 -0
- package/docs/examples/nextjs-route-handler.md +206 -0
- package/docs/examples/sandbox-vitest-suite.md +263 -0
- package/docs/index.md +66 -0
- package/docs/reference/client.md +392 -0
- package/docs/reference/errors.md +161 -0
- package/docs/reference/types.md +400 -0
- package/package.json +53 -0
package/AGENTS.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "@txnod/sdk — agent entry point"
|
|
3
|
+
description: "How AI coding agents should consume @txnod/sdk documentation shipped inside the npm tarball."
|
|
4
|
+
sdk_version: 1.0.0
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# @txnod/sdk — agent entry point
|
|
8
|
+
|
|
9
|
+
You are looking at an AI-agent-targeted documentation bundle shipped inside the `@txnod/sdk` npm tarball. Everything you need to integrate the SDK correctly is under [`./docs/`](./docs/) as plain markdown with relative links — no network access is required.
|
|
10
|
+
|
|
11
|
+
## Read order
|
|
12
|
+
|
|
13
|
+
1. [`./docs/index.md`](./docs/index.md) — full table of contents and 30-second overview.
|
|
14
|
+
2. [`./docs/00-getting-started.md`](./docs/00-getting-started.md) — install, env vars, first invoice, first verified webhook.
|
|
15
|
+
3. The numbered guide that matches the current task (`01-authentication` through `05-sandbox` through `06-idempotency`).
|
|
16
|
+
4. [`./docs/reference/client.md`](./docs/reference/client.md) — exact signature of every `TxnodClient` method.
|
|
17
|
+
|
|
18
|
+
## Non-negotiable invariants
|
|
19
|
+
|
|
20
|
+
- **Never pass a private key, mnemonic, seed, or signing material to anything in this package.** The SDK is non-custodial by construction. `apiSecret` is an HMAC secret, not a wallet key.
|
|
21
|
+
- **Always verify inbound webhooks with [`verifyWebhookSignature`](./docs/04-webhooks.md).** Never parse `req.body` before verification succeeds.
|
|
22
|
+
- **Treat every webhook as idempotent by `event_id`.** See [`./docs/06-idempotency.md`](./docs/06-idempotency.md).
|
|
23
|
+
- **Never hardcode `baseUrl`.** Omit it (defaults to `https://txnod.com`), or read from `TXNOD_BASE_URL` when overriding. Override is only warranted for a staging deployment or when pointing at a self-hosted TxNod-compatible API — the scheme is endpoint-agnostic, so the SDK works unchanged against any origin.
|
|
24
|
+
|
|
25
|
+
## What is authoritative
|
|
26
|
+
|
|
27
|
+
- **This bundle is frozen at the SDK version printed in the front-matter (`sdk_version`).** It matches the installed package exactly — no drift with a remote docs site.
|
|
28
|
+
- **Source of truth for types** is the TypeScript declarations in [`./dist/index.d.ts`](./dist/index.d.ts) (shipped alongside these docs). When markdown and `.d.ts` disagree, trust `.d.ts` and flag the discrepancy.
|
|
29
|
+
- **Link format.** All cross-references inside `./docs/` are relative `.md` paths so they resolve identically in the editor, on GitHub, and from `node_modules/@txnod/sdk/docs/` at runtime.
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@txnod/sdk` are documented here. Format: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Versioning: [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
4
|
+
|
|
5
|
+
## [Unreleased]
|
|
6
|
+
|
|
7
|
+
## [1.0.1] - 2026-05-05
|
|
8
|
+
|
|
9
|
+
Initial public release of `@txnod/sdk` — the official TypeScript client for the txnod non-custodial crypto payment gateway.
|
|
10
|
+
|
|
11
|
+
This release ships the complete partner-integration surface for the seven supported chains (BTC, ETH +ERC-20 USDT/USDC, TRON +TRC-20 USDT, Cardano, Polygon PoS +POL +Polygon USDT/USDC, BNB Smart Chain +BNB +BEP-20 USDT/USDC, TON +jetton USDT):
|
|
12
|
+
|
|
13
|
+
- `TxnodClient` — fully typed REST client covering invoice lifecycle (`create`, `get`, `cancel`, `list`), project introspection, and the `client.sandbox.*` namespace for deterministic integration testing without on-chain spend.
|
|
14
|
+
- `verifyWebhookSignature` — constant-time HMAC verifier for inbound `txnod-signature` webhook deliveries. Verify before parsing.
|
|
15
|
+
- `verifyAddress` — automatic per-invoice address verification against the operator's xpub-derived path; throws `AddressVerificationError` on mismatch. Includes `verifyTonAddress` for TON's single-wallet-per-project shape.
|
|
16
|
+
- `Txnod*Error` family — typed exceptions for every server `error_code`, including `TxnodWalletKindMismatchError` (HTTP 422, raised when a wallet's `kind` doesn't match its project's `kind`), `TxnodWalletNotBoundError` (HTTP 422, raised when the project has no verified wallet bound for the invoice's chain), and `TxnodWebhookCapacityExhaustedError` (HTTP 503, raised when the chain's webhook fleet has no spare slots — `retry_after_seconds` is `0` because partner retry alone won't free capacity; treat as a transient outage).
|
|
17
|
+
- Project / wallet `kind` discriminator — `'production' | 'testnet' | 'sandbox'`; cross-kind binding is rejected server-side. `WalletEdgeKind` (`'production' | 'testnet'`) is the type used at the kind→network edge (TonConnect, BIP32 derivation, provider URL selection).
|
|
18
|
+
- Webhook envelope `mode` field — `'production' | 'testnet' | 'sandbox'`. Branch on `event.mode` to route sandbox / testnet events away from production billing logic.
|
|
19
|
+
- **Zero peer dependencies and zero `@txnod/*` runtime coupling.** The 6 runtime deps are pure crypto primitives (`@noble/curves`, `@noble/ed25519`, `@noble/hashes`, `@scure/base`, `@scure/bip32`) and `pino` — all enforced by the [`packages/sdk/.dep-allowlist.json`](.dep-allowlist.json) audit gate; no transitive deps. All shared types are pre-expanded into `dist/_shared/index.d.ts` at build time, so the SDK works alongside any version of zod (v3, v4, v5+) — or with no zod installed at all.
|
|
20
|
+
- Bundled `AGENTS.md` + `docs/` documentation pack inside the tarball — discoverable by AI coding agents at `node_modules/@txnod/sdk/`.
|
|
21
|
+
|
|
22
|
+
Install: `npm install @txnod/sdk`. Quickstart: see the README on this package's npm page.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 TxNod <support@txnod.com>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
# @txnod/sdk
|
|
2
|
+
|
|
3
|
+
Fully-typed REST client and webhook verifier for [TxNod](https://txnod.com) — a non-custodial crypto payment gateway. Zero cryptocurrency runtime dependencies, automatic HMAC signing on every API call, RFC 7807 → typed error mapping covering every server `error_code`, and a `verifyWebhookSignature` helper with a ±300-second timestamp window. Pure Node ≥ 20 — runs unchanged in Express, Fastify, Hono, Koa, NestJS, plain `node:http`, Next.js (App Router or Pages), Nuxt, SvelteKit, Remix, Astro endpoints, or any other server-side framework. Production and testnet are both supported end-to-end, including SDK-side address verification — pick at project-create time, never per-invoice.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @txnod/sdk
|
|
9
|
+
pnpm add @txnod/sdk
|
|
10
|
+
yarn add @txnod/sdk
|
|
11
|
+
bun add @txnod/sdk
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Node ≥ 20 is required. Zero runtime and zero peer dependencies — `@txnod/sdk` is the only package you install. Types are fully expanded to plain TypeScript in the published tarball, so the SDK is compatible with any zod version your project uses (or no zod at all).
|
|
15
|
+
|
|
16
|
+
## Environment setup
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# .env.local
|
|
20
|
+
TXNOD_PROJECT_ID=01JXXXXXXXXXXXXXXXXXXXXXXX
|
|
21
|
+
TXNOD_API_SECRET=<64-hex-character API secret>
|
|
22
|
+
TXNOD_WEBHOOK_SECRET=<same as TXNOD_API_SECRET — see docs>
|
|
23
|
+
|
|
24
|
+
# Optional — defaults to https://txnod.com.
|
|
25
|
+
# TXNOD_BASE_URL=https://pay.mycompany.com
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The operator generates the project id and API secret in the TxNod dashboard ([API Keys → Generate](https://docs.txnod.com/dashboard/api-keys)). The secret is shown exactly once — copy it into your secrets manager immediately. The webhook secret is the same value as the API secret; the dashboard surfaces both names so partners can wire two distinct env vars without re-deriving the relationship.
|
|
29
|
+
|
|
30
|
+
`TXNOD_BASE_URL` is only needed when targeting a non-default origin — a staging deployment, or a self-hosted txnod-compatible gateway. The SDK's HMAC scheme, retry logic, and webhook verifier are endpoint-agnostic.
|
|
31
|
+
|
|
32
|
+
## Testing without a real wallet — sandbox mode
|
|
33
|
+
|
|
34
|
+
Sandbox projects work end-to-end without on-chain interaction: create one in the dashboard, drive `client.sandbox.simulate*` to walk the state machine, and your webhook handler receives real signed events with `mode: 'sandbox'`. The SDK surface is documented in `docs/05-sandbox.md` (bundled in this tarball at `node_modules/@txnod/sdk/docs/05-sandbox.md`); an end-to-end Vitest harness covering all seven webhook event types is at `docs/examples/sandbox-vitest-suite.md`.
|
|
35
|
+
|
|
36
|
+
## Supported coins
|
|
37
|
+
|
|
38
|
+
Operators enable coins per-project in the TxNod dashboard; a single `TxnodClient` instance can create invoices for any enabled coin — no SDK-level coin-capability toggle. The `coin` value passed to `createInvoice` must be one of the 15 literals below.
|
|
39
|
+
|
|
40
|
+
| Coin enum | Chain | Description |
|
|
41
|
+
|---|---|---|
|
|
42
|
+
| `btc` | `btc` | Bitcoin native (BTC). |
|
|
43
|
+
| `eth` | `eth` | Ethereum native (ETH). |
|
|
44
|
+
| `usdt_erc20` | `eth` | Tether USD, ERC-20 on Ethereum. |
|
|
45
|
+
| `usdc_erc20` | `eth` | USD Coin, ERC-20 on Ethereum. |
|
|
46
|
+
| `trx` | `tron` | TRON native (TRX). |
|
|
47
|
+
| `usdt_trc20` | `tron` | Tether USD, TRC-20 on TRON. |
|
|
48
|
+
| `ada` | `ada` | Cardano native (ADA). |
|
|
49
|
+
| `pol` | `polygon` | Polygon PoS native (POL). |
|
|
50
|
+
| `usdt_polygon` | `polygon` | Tether USD, ERC-20 on Polygon PoS. |
|
|
51
|
+
| `usdc_polygon` | `polygon` | USD Coin, ERC-20 on Polygon PoS. |
|
|
52
|
+
| `bnb` | `bsc` | BNB Smart Chain native (BNB). |
|
|
53
|
+
| `usdt_bep20` | `bsc` | Tether USD, BEP-20 on BNB Smart Chain. |
|
|
54
|
+
| `usdc_bep20` | `bsc` | USD Coin, BEP-20 on BNB Smart Chain. |
|
|
55
|
+
| `ton` | `ton` | TON native (Toncoin). |
|
|
56
|
+
| `usdt_ton` | `ton` | Tether USD jetton on TON. |
|
|
57
|
+
|
|
58
|
+
## SDK-side address verification (`TXNOD_<chain>_XPUB`)
|
|
59
|
+
|
|
60
|
+
When the matching env var is set, `createInvoice` automatically derives the expected deposit address from the operator's xpub at the invoice's `derivation_path` and rejects with `AddressVerificationError` on mismatch. This is the SDK's defense against a compromised gateway silently swapping the deposit address. Set per chain you accept; omit to skip verification on that chain.
|
|
61
|
+
|
|
62
|
+
| Chain | Env var | Format |
|
|
63
|
+
|---|---|---|
|
|
64
|
+
| BTC | `TXNOD_BTC_XPUB` | `zpub` (mainnet) / `vpub`/`tpub` (testnet) |
|
|
65
|
+
| ETH + ERC-20 | `TXNOD_ETH_XPUB` | `xpub` (mainnet) / `tpub` (testnet) |
|
|
66
|
+
| TRON | `TXNOD_TRON_XPUB` | `xpub` / `tpub` |
|
|
67
|
+
| Cardano | `TXNOD_CARDANO_ACCOUNT_PUBKEY` | CIP-5 `acct_xvk` bech32 |
|
|
68
|
+
| Polygon PoS | `TXNOD_POLYGON_XPUB` | `xpub` / `tpub` |
|
|
69
|
+
| BNB Smart Chain | `TXNOD_BNB_XPUB` | `xpub` / `tpub` |
|
|
70
|
+
| TON | `TXNOD_TON_PUBKEY` (+ siblings) | 64-hex Ed25519 pubkey — see below |
|
|
71
|
+
|
|
72
|
+
> **Hardware-wallet users (Ledger or Trezor):** ETH, Polygon PoS, and BNB Smart Chain share BIP-44 `coin_type 60`. One device account → one xpub → set the same value on all three env vars (`TXNOD_ETH_XPUB`, `TXNOD_POLYGON_XPUB`, `TXNOD_BNB_XPUB`). The wizard's "EVM" hint mirrors this; the SDK's per-chain address derivation differs in chain-id only. (TRON and TON are Ledger-only on the hardware-wallet side — Trezor doesn't speak either chain. Cardano via Trezor requires Model T or newer.)
|
|
73
|
+
|
|
74
|
+
Each xpub env var accepts three formats:
|
|
75
|
+
|
|
76
|
+
- **Single xpub** — the most common case: `TXNOD_BTC_XPUB=zpub6r…`.
|
|
77
|
+
- **CSV (newest-first)** — for wallet rotations where multiple xpubs must be accepted in parallel: `TXNOD_BTC_XPUB=zpub6_new,zpub6_old`. Verification iterates newest-first and accepts on the first match; an `AddressVerificationError` is raised only when *every* configured xpub fails to derive the address.
|
|
78
|
+
- **JSON array** — equivalent to CSV when you prefer explicit shape: `TXNOD_BTC_XPUB=["zpub6_new","zpub6_old"]`.
|
|
79
|
+
|
|
80
|
+
For TON the operator's wallet has no HD derivation — the address is fully determined by `(walletPublicKey, walletVersion, subwalletId, workchain)`. Configure via four env vars (defaults match a stock Ledger TON setup):
|
|
81
|
+
|
|
82
|
+
| Env var | Required | Default |
|
|
83
|
+
|---|---|---|
|
|
84
|
+
| `TXNOD_TON_PUBKEY` | yes (enables auto-verify) | — |
|
|
85
|
+
| `TXNOD_TON_WALLET_VERSION` | no | `v4R2` (allowed: `v3R2`, `v4R2`, `v5R1`) |
|
|
86
|
+
| `TXNOD_TON_SUBWALLET_ID` | no | `698983191` (standard for v3R2/v4R2) |
|
|
87
|
+
| `TXNOD_TON_WORKCHAIN` | no | `0` (basechain; allowed: `0`, `-1`) |
|
|
88
|
+
|
|
89
|
+
The pubkey is the 32-byte Ed25519 public key the operator's wallet device exports — the same value Ledger Live, Tonkeeper, etc. expose under "show recovery key" / "wallet pubkey". **Never the secret key.** When `TXNOD_TON_PUBKEY` is unset, TON verification is skipped silently — the SDK will emit one `warn` line per unverified TON invoice so operators do not silently coast on server trust.
|
|
90
|
+
|
|
91
|
+
Wallet rotations: after changing the env value in a long-lived process, call `client.refreshXpubConfig()` to pick up the new values without restarting.
|
|
92
|
+
|
|
93
|
+
### TRON requires per-address activation
|
|
94
|
+
|
|
95
|
+
TRON is the only chain in the list that charges the recipient to "activate" each fresh address before it can hold balance. TxNod's operator dashboard handles activation on the operator side; partners do nothing extra. The only partner-visible artifact is a single typed error: when an operator's TRON address pool has zero activated rows at invoice creation time, `createInvoice({ coin: 'trx' | 'usdt_trc20' })` raises `TxnodTronNoActivatedAddressesError`. The error's `walletId` field carries the operator wallet id — surface a "your operator has not finished TRON wallet setup" message and do not auto-retry; the operator must activate addresses through the dashboard before TRON invoices succeed. The canonical handler example is in `docs/02-invoices.md` (bundled in this tarball).
|
|
96
|
+
|
|
97
|
+
### TON: payment-token matching
|
|
98
|
+
|
|
99
|
+
TON is a memo chain — every TON invoice shares the operator's single deposit address and is disambiguated by an 8-hex `payment_token` placed in the on-chain transaction comment. `createInvoice({ coin: 'ton' | 'usdt_ton' })` returns the token alongside the deposit address:
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
import { TxnodClient } from '@txnod/sdk';
|
|
103
|
+
|
|
104
|
+
declare const client: TxnodClient;
|
|
105
|
+
// `qrcode` is partner-installed; the SDK does not depend on it.
|
|
106
|
+
declare const qrcode: { toDataURL: (input: string) => Promise<string> };
|
|
107
|
+
|
|
108
|
+
const invoice = await client.createInvoice({
|
|
109
|
+
amount_usd: 5,
|
|
110
|
+
coin: 'ton',
|
|
111
|
+
external_id: 'order-ton-1',
|
|
112
|
+
});
|
|
113
|
+
// invoice.payment_token === 'a1b2c3d4' (8 lowercase hex chars)
|
|
114
|
+
// invoice.payment_uri === 'ton://transfer/UQ.../?amount=5000000000&text=a1b2c3d4'
|
|
115
|
+
|
|
116
|
+
// Render the URI as a QR code on the checkout page:
|
|
117
|
+
const dataUrl: string = await qrcode.toDataURL(invoice.payment_uri);
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
The wallet apps (Tonkeeper, MyTonWallet, Ledger Live) auto-fill the `payment_token` into the comment field when the user follows the URI or scans the QR — no manual paste required. **If the user types the address into a wallet by hand and forgets the comment, the deposit lands on the operator's wallet but cannot be matched to the invoice.** Such deposits surface in the operator dashboard's "Unattributed deposits" view rather than as `invoice.paid` webhooks. Surface a "scan the QR or copy the entire `payment_uri`" instruction at checkout to keep this rare. For HD chains (BTC / ETH / TRON / ADA / Polygon / BSC), `invoice.payment_token` is always `null`.
|
|
121
|
+
|
|
122
|
+
## Quickstart — create an invoice
|
|
123
|
+
|
|
124
|
+
A complete `app/api/checkout/route.ts` against the Next.js App Router:
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
import { randomUUID } from 'node:crypto';
|
|
128
|
+
import { TxnodClient, TxnodCoinNotEnabledError, TxnodError } from '@txnod/sdk';
|
|
129
|
+
|
|
130
|
+
const client = new TxnodClient({
|
|
131
|
+
projectId: process.env.TXNOD_PROJECT_ID!,
|
|
132
|
+
apiSecret: process.env.TXNOD_API_SECRET!,
|
|
133
|
+
// baseUrl defaults to 'https://txnod.com'. Override for a self-hosted or
|
|
134
|
+
// staging deployment (see TXNOD_BASE_URL above):
|
|
135
|
+
...(process.env.TXNOD_BASE_URL ? { baseUrl: process.env.TXNOD_BASE_URL } : {}),
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
export async function POST(request: Request): Promise<Response> {
|
|
139
|
+
try {
|
|
140
|
+
const invoice = await client.createInvoice({
|
|
141
|
+
amount_usd: 9.99,
|
|
142
|
+
coin: 'usdt_trc20',
|
|
143
|
+
external_id: randomUUID(),
|
|
144
|
+
callback_url: new URL('/api/txnod-webhook', request.url).toString(),
|
|
145
|
+
});
|
|
146
|
+
return Response.json({
|
|
147
|
+
invoice_id: invoice.id,
|
|
148
|
+
pay_to: invoice.address,
|
|
149
|
+
amount_crypto: invoice.amount_crypto,
|
|
150
|
+
payment_uri: invoice.payment_uri,
|
|
151
|
+
expires_at: invoice.expires_at,
|
|
152
|
+
});
|
|
153
|
+
} catch (err) {
|
|
154
|
+
if (err instanceof TxnodCoinNotEnabledError) {
|
|
155
|
+
return Response.json(
|
|
156
|
+
{ error: 'coin_not_enabled', request_id: err.request_id },
|
|
157
|
+
{ status: 422 },
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
if (err instanceof TxnodError) {
|
|
161
|
+
return Response.json(
|
|
162
|
+
{ error: err.error_code, request_id: err.request_id },
|
|
163
|
+
{ status: err.status },
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
throw err;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Quickstart — verify a webhook
|
|
172
|
+
|
|
173
|
+
A complete `app/api/txnod-webhook/route.ts` that validates the inbound HMAC and narrows the typed event:
|
|
174
|
+
|
|
175
|
+
```ts
|
|
176
|
+
import {
|
|
177
|
+
verifyWebhookSignature,
|
|
178
|
+
TxnodHmacError,
|
|
179
|
+
TxnodTimestampError,
|
|
180
|
+
} from '@txnod/sdk';
|
|
181
|
+
|
|
182
|
+
export async function POST(request: Request): Promise<Response> {
|
|
183
|
+
const rawBody = await request.text();
|
|
184
|
+
try {
|
|
185
|
+
const event = verifyWebhookSignature(
|
|
186
|
+
request.headers,
|
|
187
|
+
rawBody,
|
|
188
|
+
process.env.TXNOD_WEBHOOK_SECRET!,
|
|
189
|
+
);
|
|
190
|
+
if (event.event_type === 'invoice.paid') {
|
|
191
|
+
// event.data is fully typed under the `invoice.paid` discriminant.
|
|
192
|
+
console.log('paid invoice', event.data.invoice_id, 'at', event.created_at_iso);
|
|
193
|
+
}
|
|
194
|
+
return Response.json({ ok: true });
|
|
195
|
+
} catch (err) {
|
|
196
|
+
if (err instanceof TxnodHmacError) {
|
|
197
|
+
return new Response('bad signature', { status: 401 });
|
|
198
|
+
}
|
|
199
|
+
if (err instanceof TxnodTimestampError) {
|
|
200
|
+
console.warn('clock skew', err.skew_seconds);
|
|
201
|
+
return new Response('stale signature', { status: 401 });
|
|
202
|
+
}
|
|
203
|
+
throw err;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Polygon PoS — create and verify (usdt_polygon)
|
|
209
|
+
|
|
210
|
+
Polygon PoS invoices settle after 128 blocks — the Heimdall checkpoint depth at which the SDK marks an `invoice.paid` event terminal. The snippet below creates a USDT-Polygon invoice and, in the webhook route, matches the inbound `invoice.paid` event against the invoice id.
|
|
211
|
+
|
|
212
|
+
```ts
|
|
213
|
+
import { randomUUID } from 'node:crypto';
|
|
214
|
+
import { TxnodClient, verifyWebhookSignature, TxnodError } from '@txnod/sdk';
|
|
215
|
+
|
|
216
|
+
const client = new TxnodClient({
|
|
217
|
+
projectId: process.env.TXNOD_PROJECT_ID!,
|
|
218
|
+
apiSecret: process.env.TXNOD_API_SECRET!,
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
const invoice = await client.createInvoice({
|
|
222
|
+
amount_usd: 25.0,
|
|
223
|
+
coin: 'usdt_polygon',
|
|
224
|
+
external_id: randomUUID(),
|
|
225
|
+
callback_url: 'https://my-site.com/api/txnod-webhook',
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
export async function POST(request: Request): Promise<Response> {
|
|
229
|
+
try {
|
|
230
|
+
const event = verifyWebhookSignature(request.headers, await request.text(), process.env.TXNOD_WEBHOOK_SECRET!);
|
|
231
|
+
if (event.event_type === 'invoice.paid' && event.data.invoice_id === invoice.id) {
|
|
232
|
+
console.log('Polygon USDT payment confirmed after 128 blocks.');
|
|
233
|
+
}
|
|
234
|
+
return Response.json({ ok: true });
|
|
235
|
+
} catch (err) {
|
|
236
|
+
if (err instanceof TxnodError) console.error(err.error_code, err.request_id);
|
|
237
|
+
throw err;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## BNB Smart Chain — create and verify (usdc_bep20)
|
|
243
|
+
|
|
244
|
+
BNB Smart Chain invoices settle after 15 blocks (BEP-126 fast-finality plus the Binance deposit convention). Note the **18-decimal trap**: `usdt_bep20` and `usdc_bep20` use 18 decimals on-chain, unlike their 6-decimal ETH / Polygon / TRON counterparts — `invoice.amount_crypto` already reflects this, so render it verbatim rather than re-scaling it.
|
|
245
|
+
|
|
246
|
+
```ts
|
|
247
|
+
import { randomUUID } from 'node:crypto';
|
|
248
|
+
import { TxnodClient, verifyWebhookSignature, TxnodError } from '@txnod/sdk';
|
|
249
|
+
|
|
250
|
+
const client = new TxnodClient({
|
|
251
|
+
projectId: process.env.TXNOD_PROJECT_ID!,
|
|
252
|
+
apiSecret: process.env.TXNOD_API_SECRET!,
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
const invoice = await client.createInvoice({
|
|
256
|
+
amount_usd: 25.0,
|
|
257
|
+
coin: 'usdc_bep20',
|
|
258
|
+
external_id: randomUUID(),
|
|
259
|
+
callback_url: 'https://my-site.com/api/txnod-webhook',
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
export async function POST(request: Request): Promise<Response> {
|
|
263
|
+
try {
|
|
264
|
+
const event = verifyWebhookSignature(request.headers, await request.text(), process.env.TXNOD_WEBHOOK_SECRET!);
|
|
265
|
+
if (event.event_type === 'invoice.paid' && event.data.invoice_id === invoice.id) {
|
|
266
|
+
console.log('BSC USDC payment confirmed after 15 blocks.');
|
|
267
|
+
}
|
|
268
|
+
return Response.json({ ok: true });
|
|
269
|
+
} catch (err) {
|
|
270
|
+
if (err instanceof TxnodError) console.error(err.error_code, err.request_id);
|
|
271
|
+
throw err;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
## Testnet — staging integrations
|
|
277
|
+
|
|
278
|
+
The kind discriminator (`'production' | 'testnet'`) is fixed at **project create time** on the dashboard, not per-invoice. Each project is bound to one kind for its entire lifetime; the SDK call site does not change between production and testnet — it is the project credential (`projectId` / `apiSecret`) that selects the chain network. To run a staging integration, create a separate testnet-kind project on the dashboard and use that project's secrets in your staging environment.
|
|
279
|
+
|
|
280
|
+
```ts
|
|
281
|
+
import { TxnodClient } from '@txnod/sdk';
|
|
282
|
+
|
|
283
|
+
// Same SDK code path. The kind is implied by the testnet project credential.
|
|
284
|
+
const client = new TxnodClient({
|
|
285
|
+
projectId: process.env.TXNOD_TESTNET_PROJECT_ID!,
|
|
286
|
+
apiSecret: process.env.TXNOD_TESTNET_API_SECRET!,
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
const invoice = await client.createInvoice({
|
|
290
|
+
amount_usd: 5.0,
|
|
291
|
+
coin: 'btc',
|
|
292
|
+
external_id: 'staging-order-1',
|
|
293
|
+
callback_url: 'https://staging.example.com/api/txnod-webhook',
|
|
294
|
+
});
|
|
295
|
+
// The webhook envelope's `mode` field carries 'testnet' for events
|
|
296
|
+
// emitted from a testnet-kind project — branch on it if your handler
|
|
297
|
+
// processes both staging and production traffic from one webhook URL.
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
The matching operator wallet on the dashboard side must be registered with the **testnet** kind (testnet-prefix xpub: `tpub`/`vpub`/`zpub` for BTC, `tpub` for ETH/Polygon/BSC/TRON, `addr_test1...` stake for Cardano). Cross-kind binding (production wallet → testnet project, or vice versa) is rejected by the server with a typed `wallet_kind_mismatch` (HTTP 422) error. Address verification on the SDK side accepts each kind's prefixes for the matching project — no flag, no separate setup. Use a testnet faucet to fund the deposit address; everything else (webhooks, finalization thresholds, idempotency) behaves the same as production, just on testnet confirmations.
|
|
301
|
+
|
|
302
|
+
## Operator-side errors your code MUST handle
|
|
303
|
+
|
|
304
|
+
Two classes of failure are caused by the operator's side, not the partner's. They cannot be auto-retried; surface them as a structured "checkout temporarily unavailable" state and notify the operator out-of-band.
|
|
305
|
+
|
|
306
|
+
| Class | When | Recovery |
|
|
307
|
+
|---|---|---|
|
|
308
|
+
| `TxnodSubscriptionExpiredError` (HTTP 402) | Operator's TxNod subscription is not `active` — writes (createInvoice, cancelInvoice, attribute) are blocked. Reads keep working | Operator renews via dashboard `/billing`. Do NOT retry |
|
|
309
|
+
| `TxnodTronNoActivatedAddressesError` (HTTP 422) | TRON-only: operator's address pool has zero activated rows | Operator activates from dashboard. Do NOT retry. `.walletId` field carries the operator wallet id for deep-link UX |
|
|
310
|
+
|
|
311
|
+
```ts
|
|
312
|
+
import {
|
|
313
|
+
TxnodClient,
|
|
314
|
+
TxnodSubscriptionExpiredError,
|
|
315
|
+
TxnodTronNoActivatedAddressesError,
|
|
316
|
+
} from '@txnod/sdk';
|
|
317
|
+
|
|
318
|
+
declare const client: TxnodClient;
|
|
319
|
+
|
|
320
|
+
export async function POST(_request: Request): Promise<Response> {
|
|
321
|
+
try {
|
|
322
|
+
await client.createInvoice({
|
|
323
|
+
external_id: 'order-1',
|
|
324
|
+
coin: 'usdt_trc20',
|
|
325
|
+
amount_usd: 9.99,
|
|
326
|
+
});
|
|
327
|
+
return Response.json({ ok: true });
|
|
328
|
+
} catch (err) {
|
|
329
|
+
if (err instanceof TxnodSubscriptionExpiredError) {
|
|
330
|
+
return Response.json({ error: 'gateway_unavailable_billing' }, { status: 503 });
|
|
331
|
+
}
|
|
332
|
+
if (err instanceof TxnodTronNoActivatedAddressesError) {
|
|
333
|
+
return Response.json(
|
|
334
|
+
{ error: 'gateway_unavailable_tron', wallet_id: err.walletId },
|
|
335
|
+
{ status: 503 },
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
throw err;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
## Client tuning options
|
|
344
|
+
|
|
345
|
+
```ts
|
|
346
|
+
import { TxnodClient } from '@txnod/sdk';
|
|
347
|
+
|
|
348
|
+
const client = new TxnodClient({
|
|
349
|
+
projectId: process.env.TXNOD_PROJECT_ID!,
|
|
350
|
+
apiSecret: process.env.TXNOD_API_SECRET!,
|
|
351
|
+
// Per-attempt HTTP timeout (default 30 s). Aborts via AbortSignal.timeout —
|
|
352
|
+
// protects against a hung upstream that would otherwise stall your request.
|
|
353
|
+
requestTimeoutMs: 15_000,
|
|
354
|
+
// Hard cap on response body size (default 1 MiB). Over-cap responses are
|
|
355
|
+
// surfaced as a typed 502 — the SDK never buffers an unbounded body.
|
|
356
|
+
maxResponseBytes: 256 * 1024,
|
|
357
|
+
// Per-attempt observer. One entry per HTTP call (success and each retry).
|
|
358
|
+
// Errors thrown from the logger are swallowed.
|
|
359
|
+
requestLogger: (e) => {
|
|
360
|
+
console.log('txnod', e.method, e.path, e.status, `${e.durationMs}ms`, e.requestId);
|
|
361
|
+
},
|
|
362
|
+
});
|
|
363
|
+
console.log(client.lastRequestId);
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
`TXNOD_SDK_LOG_LEVEL` controls the SDK's internal pino logger (default `warn`). Set to `info`/`debug` for more verbose internals. The logger redacts `xpub` and `apiSecret` keys.
|
|
367
|
+
|
|
368
|
+
## Idempotent invoice creation — `createOrGetInvoice`
|
|
369
|
+
|
|
370
|
+
If your checkout flow may retry the same `external_id` (network glitch, queue at-least-once delivery), `createOrGetInvoice` collapses the "create-then-conflict-then-search" pattern into one call:
|
|
371
|
+
|
|
372
|
+
```ts
|
|
373
|
+
import { TxnodClient } from '@txnod/sdk';
|
|
374
|
+
|
|
375
|
+
declare const client: TxnodClient;
|
|
376
|
+
|
|
377
|
+
const invoice = await client.createOrGetInvoice({
|
|
378
|
+
external_id: 'order-42',
|
|
379
|
+
coin: 'usdt_trc20',
|
|
380
|
+
amount_usd: 9.99,
|
|
381
|
+
callback_url: 'https://your-site.com/api/txnod-webhook',
|
|
382
|
+
});
|
|
383
|
+
// On TxnodExternalIdConflictError, the SDK fetches the pre-existing invoice
|
|
384
|
+
// via searchInvoices({ external_id }) and returns it. Same return shape.
|
|
385
|
+
console.log(invoice.id);
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
Use the underlying `createInvoice` if you need the `external_id_conflict` error to bubble up — for example to distinguish first-create from retried-create in your audit log.
|
|
389
|
+
|
|
390
|
+
## Error handling
|
|
391
|
+
|
|
392
|
+
Every method on `TxnodClient` throws a subclass of `TxnodError` on a non-2xx response. The base class carries `error_code`, `status`, `request_id`, and the raw RFC 7807 envelope as `raw`. The SDK ships a typed subclass for every server `error_code` (full table in `docs/reference/errors.md`, bundled in this tarball); the four most operationally useful are shown below.
|
|
393
|
+
|
|
394
|
+
```ts
|
|
395
|
+
import {
|
|
396
|
+
TxnodAuthInvalidError,
|
|
397
|
+
TxnodError,
|
|
398
|
+
TxnodPoolExhaustedError,
|
|
399
|
+
TxnodRateLimitError,
|
|
400
|
+
TxnodValidationError,
|
|
401
|
+
} from '@txnod/sdk';
|
|
402
|
+
|
|
403
|
+
export async function safeCreateInvoice(create: () => Promise<unknown>): Promise<unknown> {
|
|
404
|
+
try {
|
|
405
|
+
return await create();
|
|
406
|
+
} catch (err) {
|
|
407
|
+
if (
|
|
408
|
+
err instanceof TxnodRateLimitError ||
|
|
409
|
+
err instanceof TxnodPoolExhaustedError
|
|
410
|
+
) {
|
|
411
|
+
await new Promise((r) => setTimeout(r, err.retry_after_seconds * 1000));
|
|
412
|
+
return await create();
|
|
413
|
+
}
|
|
414
|
+
if (err instanceof TxnodValidationError) {
|
|
415
|
+
console.warn('validation failed', err.raw.errors);
|
|
416
|
+
throw err;
|
|
417
|
+
}
|
|
418
|
+
if (err instanceof TxnodAuthInvalidError) {
|
|
419
|
+
throw new Error('Re-check TXNOD_PROJECT_ID and TXNOD_API_SECRET.');
|
|
420
|
+
}
|
|
421
|
+
if (err instanceof TxnodError) {
|
|
422
|
+
console.error(err.error_code, err.request_id, err.status);
|
|
423
|
+
}
|
|
424
|
+
throw err;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
The IDE-hover JSDoc on each error class — visible in any TypeScript-aware editor — is the canonical reference. The full error matrix is documented at [docs.txnod.com/api](https://docs.txnod.com/api).
|
|
430
|
+
|
|
431
|
+
## Links
|
|
432
|
+
|
|
433
|
+
- Documentation: <https://docs.txnod.com/>
|
|
434
|
+
- API reference: <https://docs.txnod.com/api>
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// Auto-generated by scripts/bundle-shared-types.mjs — do not edit.
|
|
2
|
+
// Fully-expanded plain TypeScript types for @txnod/sdk.
|
|
3
|
+
// No zod / drizzle / @txnod/* references — safe for ANY consumer
|
|
4
|
+
// regardless of what zod (or other internal deps) they already have.
|
|
5
|
+
|
|
6
|
+
export type InvoiceStatus = "pending" | "detected" | "paid" | "overpaid" | "partial" | "expired" | "expired_paid_late" | "reverted" | "cancelled";
|
|
7
|
+
|
|
8
|
+
export type InvoiceCreateRequest = { external_id: string; coin: "btc" | "eth" | "usdt_erc20" | "usdc_erc20" | "trx" | "usdt_trc20" | "ada" | "pol" | "usdt_polygon" | "usdc_polygon" | "bnb" | "usdt_bep20" | "usdc_bep20" | "ton" | "usdt_ton"; amount_usd?: number | undefined; amount_crypto?: string | undefined; callback_url?: string | undefined; metadata?: Record<string, unknown> | undefined; };
|
|
9
|
+
|
|
10
|
+
export type InvoiceResponse = { id: string; project_id: string; external_id: string; coin: "btc" | "eth" | "usdt_erc20" | "usdc_erc20" | "trx" | "usdt_trc20" | "ada" | "pol" | "usdt_polygon" | "usdc_polygon" | "bnb" | "usdt_bep20" | "usdc_bep20" | "ton" | "usdt_ton"; address: string; amount_crypto: string; amount_crypto_units: string; amount_usd: number | null; rate_snapshot: { rate: string; source: "coingecko"; quoted_at: string; rate_is_stale: boolean; rate_age_seconds: number; } | null; payment_token: string | null; payment_uri: string; callback_url: string | null; metadata: Record<string, unknown> | null; matching_mode: "any" | "exact" | "at_least"; confirmation_threshold: number; status: "pending" | "detected" | "paid" | "overpaid" | "partial" | "expired" | "expired_paid_late" | "reverted" | "cancelled"; expires_at: number; expires_at_iso: string; created_at: number; created_at_iso: string; derivation_path?: string | undefined; verification_standard?: "bip84" | "bip44" | "cip1852" | "bip44_ed25519" | undefined; transactions?: { id: string; chain: "btc" | "eth" | "ada" | "ton" | "tron" | "polygon" | "bsc"; tx_hash: string; to_address: string | null; tx_output_index: number | null; amount_units: string; block_height: number | null; confirmations: number; received_at: number; received_at_iso: string; orphaned_at: number | null; orphaned_at_iso: string | null; }[] | undefined; confirmations?: number | undefined; };
|
|
11
|
+
|
|
12
|
+
export type InvoiceSearchQuery = { external_id?: string | undefined; address?: string | undefined; tx_hash?: string | undefined; amount?: string | undefined; status?: "pending" | "detected" | "paid" | "overpaid" | "partial" | "expired" | "expired_paid_late" | "reverted" | "cancelled" | undefined; date_from?: string | undefined; date_to?: string | undefined; cursor?: string | undefined; limit?: number | undefined; };
|
|
13
|
+
|
|
14
|
+
export type CursorPaginatedInvoiceResponse = { items: { id: string; project_id: string; external_id: string; coin: "btc" | "eth" | "usdt_erc20" | "usdc_erc20" | "trx" | "usdt_trc20" | "ada" | "pol" | "usdt_polygon" | "usdc_polygon" | "bnb" | "usdt_bep20" | "usdc_bep20" | "ton" | "usdt_ton"; address: string; amount_crypto: string; amount_crypto_units: string; amount_usd: number | null; rate_snapshot: { rate: string; source: "coingecko"; quoted_at: string; rate_is_stale: boolean; rate_age_seconds: number; } | null; payment_token: string | null; payment_uri: string; callback_url: string | null; metadata: Record<string, unknown> | null; matching_mode: "any" | "exact" | "at_least"; confirmation_threshold: number; status: "pending" | "detected" | "paid" | "overpaid" | "partial" | "expired" | "expired_paid_late" | "reverted" | "cancelled"; expires_at: number; expires_at_iso: string; created_at: number; created_at_iso: string; derivation_path?: string | undefined; verification_standard?: "bip84" | "bip44" | "cip1852" | "bip44_ed25519" | undefined; transactions?: { id: string; chain: "btc" | "eth" | "ada" | "ton" | "tron" | "polygon" | "bsc"; tx_hash: string; to_address: string | null; tx_output_index: number | null; amount_units: string; block_height: number | null; confirmations: number; received_at: number; received_at_iso: string; orphaned_at: number | null; orphaned_at_iso: string | null; }[] | undefined; confirmations?: number | undefined; }[]; next_cursor?: string | undefined; };
|
|
15
|
+
|
|
16
|
+
export type OrphanPaymentListQuery = { attributed?: boolean | undefined; chain?: "btc" | "eth" | "ada" | "ton" | "tron" | "polygon" | "bsc" | undefined; tx_hash?: string | undefined; date_from?: string | undefined; date_to?: string | undefined; amount_units_gte?: string | undefined; amount_units_lte?: string | undefined; cursor?: string | undefined; limit?: number | undefined; };
|
|
17
|
+
|
|
18
|
+
export type CursorPaginatedOrphanPaymentResponse = { items: { id: string; chain: "btc" | "eth" | "ada" | "ton" | "tron" | "polygon" | "bsc"; tx_hash: string; to_address: string; tx_output_index: number; amount_units: string; block_height: number | null; received_at: number; received_at_iso: string; attributed: boolean; attributed_invoice_id: string | null; attributed_external_id: string | null; attributed_at: number | null; attributed_at_iso: string | null; }[]; next_cursor?: string | undefined; };
|
|
19
|
+
|
|
20
|
+
export type OrphanAttributeRequest = { external_id: string; user_id?: string | undefined; metadata?: Record<string, unknown> | undefined; to_address?: string | undefined; tx_output_index?: number | undefined; };
|
|
21
|
+
|
|
22
|
+
export type WebhookEventListApiQuery = { status?: "delivered" | "retrying" | "dlq" | "skipped" | undefined; event_type?: "invoice.detected" | "invoice.paid" | "invoice.overpaid" | "invoice.partial" | "invoice.expired" | "invoice.expired_paid_late" | "invoice.reverted" | undefined; since?: string | undefined; invoice_id?: string | undefined; cursor?: string | undefined; limit?: number | undefined; };
|
|
23
|
+
|
|
24
|
+
export type WebhookEventListResponse = { items: { id: string; event_type: "invoice.detected" | "invoice.paid" | "invoice.overpaid" | "invoice.partial" | "invoice.expired" | "invoice.expired_paid_late" | "invoice.reverted"; status: "delivered" | "retrying" | "dlq" | "skipped"; created_at: string; target_url: string | null; attempt_count: number; last_response_status: number | null; invoice_id: string | null; dlq_at: string | null; delivered_at: string | null; skip_reason: "not_subscribed" | "no_target_url" | null; }[]; next_cursor?: string | undefined; };
|
|
25
|
+
|
|
26
|
+
export type WebhookEventResendResponse = { event_id: string; original_event_id: string; event_type: "invoice.detected" | "invoice.paid" | "invoice.overpaid" | "invoice.partial" | "invoice.expired" | "invoice.expired_paid_late" | "invoice.reverted"; project_id: string; invoice_id: string | null; target_url: string | null; created_at: number; created_at_iso: string; };
|
|
27
|
+
|
|
28
|
+
export type WebhookEvent = { event_id: string; event_type: "invoice.detected"; created_at: number; created_at_iso: string; project_id: string; data: { invoice_id: string; project_id: string; chain: "btc" | "eth" | "ada" | "ton" | "tron" | "polygon" | "bsc"; coin: "btc" | "eth" | "usdt_erc20" | "usdc_erc20" | "trx" | "usdt_trc20" | "ada" | "pol" | "usdt_polygon" | "usdc_polygon" | "bnb" | "usdt_bep20" | "usdc_bep20" | "ton" | "usdt_ton"; tx_hash: string; to_address: string | null; amount_units: string; confirmations: number; block_height: number | null; payment_token: string | null; matched_payment_token: string | null; chain_specific: { ton?: { tx_lt: string; mc_block_seqno: number; block_ref: { workchain: number; shard: string; seqno: number; }; jetton_master?: string | undefined; } | undefined; } | null; reason?: "reorg" | "late_arrival" | undefined; }; attempt: number; mode: "production" | "testnet" | "sandbox"; } | { event_id: string; event_type: "invoice.paid"; created_at: number; created_at_iso: string; project_id: string; data: { invoice_id: string; project_id: string; chain: "btc" | "eth" | "ada" | "ton" | "tron" | "polygon" | "bsc"; coin: "btc" | "eth" | "usdt_erc20" | "usdc_erc20" | "trx" | "usdt_trc20" | "ada" | "pol" | "usdt_polygon" | "usdc_polygon" | "bnb" | "usdt_bep20" | "usdc_bep20" | "ton" | "usdt_ton"; tx_hash: string; to_address: string | null; amount_units: string; confirmations: number; block_height: number | null; payment_token: string | null; matched_payment_token: string | null; chain_specific: { ton?: { tx_lt: string; mc_block_seqno: number; block_ref: { workchain: number; shard: string; seqno: number; }; jetton_master?: string | undefined; } | undefined; } | null; reason?: "reorg" | "late_arrival" | undefined; }; attempt: number; mode: "production" | "testnet" | "sandbox"; } | { event_id: string; event_type: "invoice.overpaid"; created_at: number; created_at_iso: string; project_id: string; data: { invoice_id: string; project_id: string; chain: "btc" | "eth" | "ada" | "ton" | "tron" | "polygon" | "bsc"; coin: "btc" | "eth" | "usdt_erc20" | "usdc_erc20" | "trx" | "usdt_trc20" | "ada" | "pol" | "usdt_polygon" | "usdc_polygon" | "bnb" | "usdt_bep20" | "usdc_bep20" | "ton" | "usdt_ton"; tx_hash: string; to_address: string | null; amount_units: string; confirmations: number; block_height: number | null; payment_token: string | null; matched_payment_token: string | null; chain_specific: { ton?: { tx_lt: string; mc_block_seqno: number; block_ref: { workchain: number; shard: string; seqno: number; }; jetton_master?: string | undefined; } | undefined; } | null; reason?: "reorg" | "late_arrival" | undefined; }; attempt: number; mode: "production" | "testnet" | "sandbox"; } | { event_id: string; event_type: "invoice.partial"; created_at: number; created_at_iso: string; project_id: string; data: { invoice_id: string; project_id: string; chain: "btc" | "eth" | "ada" | "ton" | "tron" | "polygon" | "bsc"; coin: "btc" | "eth" | "usdt_erc20" | "usdc_erc20" | "trx" | "usdt_trc20" | "ada" | "pol" | "usdt_polygon" | "usdc_polygon" | "bnb" | "usdt_bep20" | "usdc_bep20" | "ton" | "usdt_ton"; tx_hash: string; to_address: string | null; amount_units: string; confirmations: number; block_height: number | null; payment_token: string | null; matched_payment_token: string | null; chain_specific: { ton?: { tx_lt: string; mc_block_seqno: number; block_ref: { workchain: number; shard: string; seqno: number; }; jetton_master?: string | undefined; } | undefined; } | null; reason?: "reorg" | "late_arrival" | undefined; }; attempt: number; mode: "production" | "testnet" | "sandbox"; } | { event_id: string; event_type: "invoice.expired"; created_at: number; created_at_iso: string; project_id: string; data: { invoice_id: string; project_id: string; chain: "btc" | "eth" | "ada" | "ton" | "tron" | "polygon" | "bsc"; coin: "btc" | "eth" | "usdt_erc20" | "usdc_erc20" | "trx" | "usdt_trc20" | "ada" | "pol" | "usdt_polygon" | "usdc_polygon" | "bnb" | "usdt_bep20" | "usdc_bep20" | "ton" | "usdt_ton"; tx_hash: string; to_address: string | null; amount_units: string; confirmations: number; block_height: number | null; payment_token: string | null; matched_payment_token: string | null; chain_specific: { ton?: { tx_lt: string; mc_block_seqno: number; block_ref: { workchain: number; shard: string; seqno: number; }; jetton_master?: string | undefined; } | undefined; } | null; reason?: "reorg" | "late_arrival" | undefined; }; attempt: number; mode: "production" | "testnet" | "sandbox"; } | { event_id: string; event_type: "invoice.expired_paid_late"; created_at: number; created_at_iso: string; project_id: string; data: { invoice_id: string; project_id: string; chain: "btc" | "eth" | "ada" | "ton" | "tron" | "polygon" | "bsc"; coin: "btc" | "eth" | "usdt_erc20" | "usdc_erc20" | "trx" | "usdt_trc20" | "ada" | "pol" | "usdt_polygon" | "usdc_polygon" | "bnb" | "usdt_bep20" | "usdc_bep20" | "ton" | "usdt_ton"; tx_hash: string; to_address: string | null; amount_units: string; confirmations: number; block_height: number | null; payment_token: string | null; matched_payment_token: string | null; chain_specific: { ton?: { tx_lt: string; mc_block_seqno: number; block_ref: { workchain: number; shard: string; seqno: number; }; jetton_master?: string | undefined; } | undefined; } | null; reason?: "reorg" | "late_arrival" | undefined; }; attempt: number; mode: "production" | "testnet" | "sandbox"; } | { event_id: string; event_type: "invoice.reverted"; created_at: number; created_at_iso: string; project_id: string; data: { invoice_id: string; project_id: string; chain: "btc" | "eth" | "ada" | "ton" | "tron" | "polygon" | "bsc"; coin: "btc" | "eth" | "usdt_erc20" | "usdc_erc20" | "trx" | "usdt_trc20" | "ada" | "pol" | "usdt_polygon" | "usdc_polygon" | "bnb" | "usdt_bep20" | "usdc_bep20" | "ton" | "usdt_ton"; tx_hash: string; to_address: string | null; amount_units: string; confirmations: number; block_height: number | null; payment_token: string | null; matched_payment_token: string | null; chain_specific: { ton?: { tx_lt: string; mc_block_seqno: number; block_ref: { workchain: number; shard: string; seqno: number; }; jetton_master?: string | undefined; } | undefined; } | null; reason?: "reorg" | "late_arrival" | undefined; }; attempt: number; mode: "production" | "testnet" | "sandbox"; };
|
|
29
|
+
|
|
30
|
+
export type WebhookEventData = { invoice_id: string; project_id: string; chain: "btc" | "eth" | "ada" | "ton" | "tron" | "polygon" | "bsc"; coin: "btc" | "eth" | "usdt_erc20" | "usdc_erc20" | "trx" | "usdt_trc20" | "ada" | "pol" | "usdt_polygon" | "usdc_polygon" | "bnb" | "usdt_bep20" | "usdc_bep20" | "ton" | "usdt_ton"; tx_hash: string; to_address: string | null; amount_units: string; confirmations: number; block_height: number | null; payment_token: string | null; matched_payment_token: string | null; chain_specific: { ton?: { tx_lt: string; mc_block_seqno: number; block_ref: { workchain: number; shard: string; seqno: number; }; jetton_master?: string | undefined; } | undefined; } | null; reason?: "reorg" | "late_arrival" | undefined; };
|
|
31
|
+
|
|
32
|
+
export type WebhookEventMode = "production" | "testnet" | "sandbox";
|
|
33
|
+
|
|
34
|
+
export type WebhookEventType = "invoice.detected" | "invoice.paid" | "invoice.overpaid" | "invoice.partial" | "invoice.expired" | "invoice.expired_paid_late" | "invoice.reverted";
|
|
35
|
+
|
|
36
|
+
export type RatesQuery = { coins?: string | undefined; };
|
|
37
|
+
|
|
38
|
+
export type RatesResponse = { quoted_at: string; source: "coingecko"; rates: Partial<Record<"btc" | "eth" | "usdt_erc20" | "usdc_erc20" | "trx" | "usdt_trc20" | "ada" | "pol" | "usdt_polygon" | "usdc_polygon" | "bnb" | "usdt_bep20" | "usdc_bep20" | "ton" | "usdt_ton", { rate: string; rate_is_stale: boolean; rate_age_seconds: number; }>>; indicative_notice: string; };
|
|
39
|
+
|
|
40
|
+
export type QuoteQuery = { amount_usd: number; coins?: string | undefined; };
|
|
41
|
+
|
|
42
|
+
export type QuoteResponse = { amount_usd: number; quoted_at: string; source: "coingecko"; quotes: Partial<Record<"btc" | "eth" | "usdt_erc20" | "usdc_erc20" | "trx" | "usdt_trc20" | "ada" | "pol" | "usdt_polygon" | "usdc_polygon" | "bnb" | "usdt_bep20" | "usdc_bep20" | "ton" | "usdt_ton", { amount_crypto: string; amount_crypto_units: string; rate: string; rate_is_stale: boolean; rate_age_seconds: number; }>>; indicative_notice: string; };
|
|
43
|
+
|
|
44
|
+
export type ErrorCode = "validation_error" | "invalid_coin" | "invalid_xpub_format" | "invalid_webhook_url" | "auth_invalid" | "signature_invalid" | "signature_replayed" | "timestamp_out_of_window" | "key_suspended" | "project_suspended" | "permission_denied" | "key_revoked" | "invoice_not_found" | "project_not_found" | "wallet_not_found" | "external_id_conflict" | "xpub_not_verified" | "coin_not_enabled" | "amount_out_of_range" | "rate_limit_exceeded" | "pool_exhausted" | "webhook_capacity_exhausted" | "duplicate_provider_webhook_id" | "otp_expired" | "otp_used" | "invite_invalid" | "internal_error" | "invoice_not_cancellable" | "invalid_state_transition" | "orphan_not_found" | "orphan_already_attributed" | "event_not_found" | "wallet_not_bound" | "wallet_not_owned" | "wallet_has_active_bindings" | "wallet_kind_mismatch" | "subscription_expired" | "tron_no_activated_addresses_available" | "ton_operator_wallet_not_deployed" | "ton_invalid_wallet_version" | "ton_jetton_resolve_failed" | "ton_comment_parse_failed" | "tonconnect_payload_expired" | "tonconnect_payload_unknown" | "tonconnect_domain_mismatch" | "tonconnect_timestamp_skew" | "tonconnect_unknown_wallet_version" | "tonconnect_signature_invalid" | "tonconnect_network_mismatch" | "sandbox_project_required" | "production_project_required" | "sandbox_per_operator_cap_reached" | "sandbox_key_against_production_project" | "production_key_against_sandbox_project" | "sandbox_provisioning_failed" | "sandbox_invoice_transition_invalid" | "sandbox_invoice_not_found" | "sandbox_invoice_terminal" | "sandbox_rate_limit_exceeded" | "sandbox_reset_failed" | "sandbox_delete_failed" | "sandbox_active_invoice_cap_reached";
|
|
45
|
+
|
|
46
|
+
export type ProblemDetails = { type: "about:blank"; title: string; status: number; error_code: "validation_error" | "invalid_coin" | "invalid_xpub_format" | "invalid_webhook_url" | "auth_invalid" | "signature_invalid" | "signature_replayed" | "timestamp_out_of_window" | "key_suspended" | "project_suspended" | "permission_denied" | "key_revoked" | "invoice_not_found" | "project_not_found" | "wallet_not_found" | "external_id_conflict" | "xpub_not_verified" | "coin_not_enabled" | "amount_out_of_range" | "rate_limit_exceeded" | "pool_exhausted" | "webhook_capacity_exhausted" | "duplicate_provider_webhook_id" | "otp_expired" | "otp_used" | "invite_invalid" | "internal_error" | "invoice_not_cancellable" | "invalid_state_transition" | "orphan_not_found" | "orphan_already_attributed" | "event_not_found" | "wallet_not_bound" | "wallet_not_owned" | "wallet_has_active_bindings" | "wallet_kind_mismatch" | "subscription_expired" | "tron_no_activated_addresses_available" | "ton_operator_wallet_not_deployed" | "ton_invalid_wallet_version" | "ton_jetton_resolve_failed" | "ton_comment_parse_failed" | "tonconnect_payload_expired" | "tonconnect_payload_unknown" | "tonconnect_domain_mismatch" | "tonconnect_timestamp_skew" | "tonconnect_unknown_wallet_version" | "tonconnect_signature_invalid" | "tonconnect_network_mismatch" | "sandbox_project_required" | "production_project_required" | "sandbox_per_operator_cap_reached" | "sandbox_key_against_production_project" | "production_key_against_sandbox_project" | "sandbox_provisioning_failed" | "sandbox_invoice_transition_invalid" | "sandbox_invoice_not_found" | "sandbox_invoice_terminal" | "sandbox_rate_limit_exceeded" | "sandbox_reset_failed" | "sandbox_delete_failed" | "sandbox_active_invoice_cap_reached"; request_id: string; errors?: unknown[] | undefined; wallet_id?: string | undefined; current_status?: string | undefined; requested_event?: string | undefined; current_count?: number | undefined; reset_url?: string | undefined; failed_step?: string | null | undefined; wallet_kind?: "production" | "testnet" | "sandbox" | undefined; project_kind?: "production" | "testnet" | "sandbox" | undefined; };
|
|
47
|
+
|
|
48
|
+
export type Chain = "btc" | "eth" | "ada" | "ton" | "tron" | "polygon" | "bsc";
|
|
49
|
+
|
|
50
|
+
export type Coin = "btc" | "eth" | "usdt_erc20" | "usdc_erc20" | "trx" | "usdt_trc20" | "ada" | "pol" | "usdt_polygon" | "usdc_polygon" | "bnb" | "usdt_bep20" | "usdc_bep20" | "ton" | "usdt_ton";
|
|
51
|
+
|
|
52
|
+
export type WalletEdgeKind = "production" | "testnet";
|
|
53
|
+
|
|
54
|
+
export type ClockAdvance = { chain: "btc" | "eth" | "ada" | "ton" | "tron" | "polygon" | "bsc"; blocks: number; };
|
|
55
|
+
|
|
56
|
+
export type SimulateEvent = { eventType: "invoice.detected" | "invoice.paid" | "invoice.overpaid" | "invoice.partial" | "invoice.expired" | "invoice.expired_paid_late" | "invoice.reverted"; amountUnits: string; confirmations: number; blockHeight: number; expectedCurrentStatus: "pending" | "detected" | "paid" | "overpaid" | "partial" | "expired" | "expired_paid_late" | "reverted" | "cancelled"; chainSpecific?: unknown; seed?: string | undefined; };
|
|
57
|
+
|
|
58
|
+
export type SimulateLatePayment = { amountUnits?: string | undefined; seed?: string | undefined; };
|
|
59
|
+
|
|
60
|
+
export type SimulateOverpaid = { multiplier?: number | undefined; extraUnits?: string | undefined; seed?: string | undefined; };
|
|
61
|
+
|
|
62
|
+
export type SimulatePartial = { fraction?: number | undefined; amountUnits?: string | undefined; seed?: string | undefined; };
|
|
63
|
+
|
|
64
|
+
export type WalletsListResponse = { items: { chain: "btc" | "eth" | "ada" | "ton" | "tron" | "polygon" | "bsc"; xpub: string | null; derivation_path: string; stake_address: string | null; ed25519_pubkey_hex: string | null; }[]; };
|
|
65
|
+
|
|
66
|
+
export declare const ERROR_CODES: readonly ["validation_error", "invalid_coin", "invalid_xpub_format", "invalid_webhook_url", "auth_invalid", "signature_invalid", "signature_replayed", "timestamp_out_of_window", "key_suspended", "project_suspended", "permission_denied", "key_revoked", "invoice_not_found", "project_not_found", "wallet_not_found", "external_id_conflict", "xpub_not_verified", "coin_not_enabled", "amount_out_of_range", "rate_limit_exceeded", "pool_exhausted", "webhook_capacity_exhausted", "duplicate_provider_webhook_id", "otp_expired", "otp_used", "invite_invalid", "internal_error", "invoice_not_cancellable", "invalid_state_transition", "orphan_not_found", "orphan_already_attributed", "event_not_found", "wallet_not_bound", "wallet_not_owned", "wallet_has_active_bindings", "wallet_kind_mismatch", "subscription_expired", "tron_no_activated_addresses_available", "ton_operator_wallet_not_deployed", "ton_invalid_wallet_version", "ton_jetton_resolve_failed", "ton_comment_parse_failed", "tonconnect_payload_expired", "tonconnect_payload_unknown", "tonconnect_domain_mismatch", "tonconnect_timestamp_skew", "tonconnect_unknown_wallet_version", "tonconnect_signature_invalid", "tonconnect_network_mismatch", "sandbox_project_required", "production_project_required", "sandbox_per_operator_cap_reached", "sandbox_key_against_production_project", "production_key_against_sandbox_project", "sandbox_provisioning_failed", "sandbox_invoice_transition_invalid", "sandbox_invoice_not_found", "sandbox_invoice_terminal", "sandbox_rate_limit_exceeded", "sandbox_reset_failed", "sandbox_delete_failed", "sandbox_active_invoice_cap_reached"];
|
|
67
|
+
|
|
68
|
+
export declare const ERROR_CODE_STATUS: { readonly validation_error: 400; readonly invalid_coin: 400; readonly invalid_xpub_format: 400; readonly invalid_webhook_url: 400; readonly auth_invalid: 401; readonly signature_invalid: 401; readonly signature_replayed: 401; readonly timestamp_out_of_window: 401; readonly key_suspended: 403; readonly project_suspended: 403; readonly permission_denied: 403; readonly key_revoked: 403; readonly invoice_not_found: 404; readonly project_not_found: 404; readonly wallet_not_found: 404; readonly external_id_conflict: 409; readonly xpub_not_verified: 409; readonly coin_not_enabled: 422; readonly amount_out_of_range: 422; readonly rate_limit_exceeded: 429; readonly pool_exhausted: 503; readonly webhook_capacity_exhausted: 503; readonly duplicate_provider_webhook_id: 409; readonly otp_expired: 400; readonly otp_used: 400; readonly invite_invalid: 400; readonly internal_error: 500; readonly invoice_not_cancellable: 409; readonly invalid_state_transition: 409; readonly orphan_not_found: 404; readonly orphan_already_attributed: 409; readonly event_not_found: 404; readonly wallet_not_bound: 422; readonly wallet_not_owned: 403; readonly wallet_has_active_bindings: 409; readonly wallet_kind_mismatch: 422; readonly subscription_expired: 402; readonly tron_no_activated_addresses_available: 422; readonly ton_operator_wallet_not_deployed: 422; readonly ton_invalid_wallet_version: 422; readonly ton_jetton_resolve_failed: 503; readonly ton_comment_parse_failed: 422; readonly tonconnect_payload_expired: 400; readonly tonconnect_payload_unknown: 400; readonly tonconnect_domain_mismatch: 400; readonly tonconnect_timestamp_skew: 400; readonly tonconnect_unknown_wallet_version: 400; readonly tonconnect_signature_invalid: 400; readonly tonconnect_network_mismatch: 400; readonly sandbox_project_required: 403; readonly production_project_required: 403; readonly sandbox_per_operator_cap_reached: 422; readonly sandbox_key_against_production_project: 400; readonly production_key_against_sandbox_project: 400; readonly sandbox_provisioning_failed: 500; readonly sandbox_invoice_transition_invalid: 422; readonly sandbox_invoice_not_found: 404; readonly sandbox_invoice_terminal: 422; readonly sandbox_rate_limit_exceeded: 429; readonly sandbox_reset_failed: 500; readonly sandbox_delete_failed: 500; readonly sandbox_active_invoice_cap_reached: 422; };
|