@atumlabs/payment-gateway-client 1.0.2 → 2.1.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/CHANGELOG.md CHANGED
@@ -5,6 +5,45 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [2.1.0] - 2026-07-31
9
+
10
+ ### Added
11
+ - The CLIs read an optional `.env` file from the working directory, so `cp .env.example .env` configures them. Resolution order: a CLI flag, then the environment, then `.env`, then the built-in default. This applies to the CLIs only; the SDK reads the environment but never modifies it, so an application embedding the SDK stays in control of its own configuration.
12
+ - `getErrorResponse(err)` returns the typed, public-facing gateway error (`ErrorResponse` — `code`, `message`, `request_id?`, `docs_url?`, `domain?`) from a caught `ApiError`, or `undefined` for anything else; `isApiError(err)` type guard for the transport-level error. No internal error taxonomy is exposed.
13
+ - Idempotency and retries documentation (`docs/idempotency.md`) plus a summary in the README: the two guarantees (gateway dedup and on-chain single-settlement) and the per-chain differences (EVM/Tron vs Solana).
14
+ - The published package now ships `LICENSE` and an autogenerated `THIRD-PARTY-NOTICES.txt` (attributing the third-party components statically bundled into `dist/`).
15
+ - The gateway base URL now honors a `GATEWAY_URL` environment variable. Precedence: an explicit URL (SDK `{ BASE }` or the CLI `--gateway` flag), then `GATEWAY_URL`, then the built-in production-testnet default. A blank or whitespace-only `GATEWAY_URL` counts as unset and falls through to the default. An explicit `{ BASE: '' }` is used verbatim, which is how a caller targets a same-origin proxy.
16
+ - The exported `OpenAPI` configuration now reports this package's default gateway (production-testnet), matching what a client resolves when no URL is supplied. The OpenAPI contract continues to list the mainnet server first, in line with the other Atum service contracts.
17
+
18
+ ### Changed
19
+ - README signing example now uses the shipped signer helpers (`createSenderSigner` + `signPaymentRequest`) instead of manual signing, and the error-handling example reads the typed `ErrorResponse` fields.
20
+ - The idempotency docs now state the consequence of reusing a `request_id` with different terms: the gateway returns the original payment, so the new terms are silently dropped and a genuinely new payment needs a new id.
21
+ - The `fulfillment_verifier.endpoint` example in the OpenAPI spec is now a bare origin (`https://veri-fill.production-testnet.atum.xyz`) and its description says so. The field is a base URL to which the caller appends the verifier's own paths, so an example carrying `/v1/fulfillment` would double the path for anyone copying its shape.
22
+ - Two documentation links in the OpenAPI contract now point at `schemas.atum.xyz`. Descriptive text only: JSON-LD `@context` prefixes, schema `$id` values, and `did:web:` identifiers are unchanged, since those take part in signature canonicalization.
23
+ - The package is marked `restricted` and its `license` field is `SEE LICENSE IN LICENSE`. The publish guard now also fails on any inlined copyleft dependency, stale/incomplete third-party notices, missing license materials in the tarball, or an incorrect `license` field.
24
+ - Default gateway hosts point at the canonical `payment-gw.production-{testnet,mainnet}.atum.xyz` endpoints (the SDK/CLI default and the generated client default), replacing the retired `atumlabs.xyz` / `api.atum.network` hosts.
25
+
26
+ ### Fixed
27
+ - The CLIs (`send-payment`, `request-quote`, `quote-status`, `payment-status`) report the real package version via `--version` (they previously hardcoded `1.0.0`).
28
+ - `docs/` is now included in the published package. The README links to `docs/idempotency.md`, which had not been shipped, so the link was dead for anyone installing from npm.
29
+ - README corrections: the install instructions now distinguish a global install (for the command-line tools) from a project install (for the SDK), and the removal instructions match; the `.env` file and the gateway-URL precedence are documented; monorepo build detail moved to `CONTRIBUTING.md`.
30
+ - A zero-config client (`new PaymentGatewayClient()` with no `BASE`) now uses a single, consistent gateway host; previously it fetched chain defaults from the testnet host but submitted payments to the mainnet host.
31
+
32
+ ## [2.0.0] - 2026-07-27
33
+
34
+ ### Breaking
35
+ - `request_id` is now required on `preparePaymentRequest` (the client no longer silently auto-generates one, which could turn a retry into a second payment). Callers must supply a stable `request_id` and reuse it on retry. The `send-payment` CLI generates a one-shot id when `--request-id` is omitted.
36
+ - An explicit `deadlineSeconds` that is shorter than the settlement window (`fulfillmentDeadlineSeconds`) is now rejected — the deposit permit must stay valid until settlement.
37
+ - Solana now honors an explicit `nonce` (it was ignored on Solana in 1.0.2) and validates it at build time: a caller-supplied nonce must fit an unsigned 64-bit integer and its low byte (the on-chain replay slot) must be `< 235`, otherwise the build throws instead of failing later on-chain. Omitting `nonce` still derives it deterministically as before.
38
+
39
+ ### Changed
40
+ - Deposits are now built and signed through the shared `@atum-labs/payment-request-sender-auth` library instead of the client's own copy of that logic (single source of truth across the payment stack). The public signing API (`createSenderSigner`, `signPaymentRequest`, `resolveTurnkeyAddresses`) is unchanged.
41
+ - The EVM/Tron deposit permit deadline now tracks the payment's settlement (`fulfillment_deadline`) instead of a fixed far-future date, so the authorization's validity window is meaningful.
42
+
43
+ ### Added
44
+ - The deposit's single-use nonce is now derived deterministically from `request_id` + depositor, so rebuilding the same payment (e.g. on retry) reproduces the same single-use nonce. The guarantee differs by chain: on EVM/Tron the Permit2 nonce is a permanent on-chain bitmap, so of any number of rebuilds only one deposit can ever settle; on Solana the escrow replay nonce protects only within a ~128s window (`issued_at` is re-read per build), and the gateway's `request_id` dedup is the durable backstop beyond it — pin `issued_at` via `solanaClockReader` to keep a rebuild inside the same window.
45
+ - The depositor address is canonicalized before it seeds the nonce: EVM `0x` addresses are lower-cased (so a checksummed and a lowercase address derive the same nonce), while case-sensitive base58 (Solana/Tron) is used verbatim.
46
+
8
47
  ## [1.0.2] - 2026-07-17
9
48
 
10
49
  ### Added
package/README.md CHANGED
@@ -2,25 +2,38 @@
2
2
 
3
3
  TypeScript client for Atum Payment Gateway API with CLI support.
4
4
 
5
+ > **Proprietary software - not open source.**
6
+ >
7
+ > Copyright (c) 2026 Atum Labs, Inc. All rights reserved. Access to and use of `@atumlabs/payment-gateway-client` are limited to entities expressly authorized by Atum and are governed by the Atum Payment Gateway Client Private Repository License Agreement in the LICENSE file included with this package. Do not redistribute, publish, mirror, sublicense, or provide this package to any unauthorized person. By accessing, installing, copying, or using the package, you agree to the license terms.
8
+
5
9
  > NOTE: Payments from EVM chains require prior ERC-20 approval on the source token for the Permit2 contract (0x000000000022D473030F116dDEE9F6B43aC78BA3 on virtually all EVM chains).
6
10
  >
7
- > (And the same applies for Tron/TRC-20, with a Permit2 address of TJhMXTHQHeQyMD7TcKQFqAePNgG4b31H9m on mainnet or TPUqJPASUn1zLvbLBgRZ5pBYrx7WSe5ahp on Shasta)`)
11
+ > (And the same applies for Tron/TRC-20, with a Permit2 address of TJhMXTHQHeQyMD7TcKQFqAePNgG4b31H9m on mainnet or TPUqJPASUn1zLvbLBgRZ5pBYrx7WSe5ahp on Shasta).
8
12
 
9
13
  ## Installation
10
14
 
11
15
  `@atumlabs/payment-gateway-client` is a private npm package. Once your npm account
12
- has been granted access, install it with npm:
16
+ has been granted access, install it with npm.
17
+
18
+ To use the SDK in a project:
13
19
 
14
20
  ```bash
15
21
  npm install @atumlabs/payment-gateway-client
16
22
  ```
17
23
 
18
- This also installs the `send-payment`, `request-quote`, `quote-status`, and
19
- `payment-status` CLI commands.
24
+ To use the command-line tools, install globally so they are on your `PATH`:
25
+
26
+ ```bash
27
+ npm install -g @atumlabs/payment-gateway-client
28
+ ```
29
+
30
+ A project-local install also provides the commands, under `node_modules/.bin`, so
31
+ `npx send-payment ...` works without a global install.
20
32
 
21
33
  ## CLI Usage
22
34
 
23
- After linking, the `send-payment` command is available globally:
35
+ The package provides four commands: `send-payment`, `request-quote`,
36
+ `quote-status`, and `payment-status`. After a global install:
24
37
 
25
38
  ```bash
26
39
  send-payment [options] <sender> <amount> <sourceAsset> <receiver> <destinationAsset>
@@ -38,8 +51,8 @@ send-payment [options] <sender> <amount> <sourceAsset> <receiver> <destinationAs
38
51
 
39
52
  - `-V, --version` - Output the version number
40
53
  - `--gateway <url>` - Payment gateway URL (default: testnet)
41
- - `--request-id <id>` - Custom request ID (overrides prefix)
42
- - `--request-id-prefix <prefix>` - Custom request ID prefix (default: `pmt-gw-cli`)
54
+ - `--request-id <id>` - Idempotency key; seeds the on-chain deposit nonce. Reuse the same id to retry a payment safely. Omitted: a one-shot id is generated and printed (see [Idempotency and retries](#idempotency-and-retries))
55
+ - `--request-id-prefix <prefix>` - Prefix for the auto-generated request id (default: `pmt-gw-cli`)
43
56
  - `-h, --help` - Display help
44
57
 
45
58
  ### CAIP-19 Asset Format Examples
@@ -75,19 +88,32 @@ export TURNKEY_API_PRIVATE_KEY=...
75
88
  send-payment --provider turnkey <args...>
76
89
  ```
77
90
 
78
- Turnkey signing uses the shared `@atum-labs/turnkey-signer` (and `@atum-labs/km-core`),
79
- which live in this monorepo under `key-management/` and are consumed as pnpm workspace
80
- packages (`workspace:*`), built locally by the `build:deps` step. `@solana/web3.js` and
81
- the other Turnkey deps are already declared, so no extra setup is required.
91
+ Everything Turnkey signing needs is already declared as a dependency, so no extra
92
+ setup is required. The Turnkey code is loaded on demand, so the private-key path
93
+ does not pull in Turnkey or `@solana/web3.js`.
94
+
95
+ ### Configuration file
96
+
97
+ The command-line tools also read an optional `.env` file from the directory you
98
+ run them in, so credentials and settings do not have to be retyped each time:
99
+
100
+ ```
101
+ PRIVATE_KEY=0x...
102
+ GATEWAY_URL=https://payment-gw.production-testnet.atum.xyz
103
+ SOLANA_RPC_URL=
104
+ TURNKEY_ORGANIZATION_ID=
105
+ TURNKEY_WALLET_ID=
106
+ TURNKEY_API_PUBLIC_KEY=
107
+ TURNKEY_API_PRIVATE_KEY=
108
+ ```
82
109
 
83
- Notes:
84
- - The shared packages are workspace members, so a root `pnpm install` links them, and
85
- `pnpm run build` and `pnpm test` build them first (`build:deps`).
86
- - The Turnkey code is loaded lazily (`import('./turnkey-impl')`), so the private-key
87
- path never pulls in Turnkey or `@solana/web3.js`.
88
- - For publishing, the build (tsup) bundles the shared `@atum-labs/*` packages directly
89
- into `dist`, so the published package is self-contained with no `@atum-labs/*` runtime
90
- dependencies. The siblings stay `workspace:*` devDependencies used only at build time.
110
+ Where a setting has a matching flag, the flag takes precedence, then a value
111
+ already set in your environment, then `.env`, then the built-in default. Keep the
112
+ file out of version control — it holds signing keys.
113
+
114
+ This applies to the command-line tools only. The SDK does not read `.env`; pass
115
+ configuration as arguments, or set `GATEWAY_URL` in your own application's
116
+ environment.
91
117
 
92
118
  ### Output
93
119
 
@@ -105,12 +131,10 @@ PRIVATE_KEY=0xabc... send-payment \
105
131
  tron:shasta/trc20:TG3XXyExBkPp9nzdajDZsozEu4BkaSJozs
106
132
  ```
107
133
 
108
- ### Unlinking
109
-
110
- To remove the global CLI command:
134
+ ### Removing the command-line tools
111
135
 
112
136
  ```bash
113
- npm unlink -g @atumlabs/payment-gateway-client
137
+ npm uninstall -g @atumlabs/payment-gateway-client
114
138
  ```
115
139
 
116
140
  ## SDK Usage
@@ -118,18 +142,31 @@ npm unlink -g @atumlabs/payment-gateway-client
118
142
  ### Basic Setup
119
143
 
120
144
  ```typescript
121
- import {
145
+ import {
122
146
  PaymentGatewayClient,
147
+ createSenderSigner,
148
+ signPaymentRequest,
149
+ getErrorResponse,
123
150
  type PaymentResponse,
124
- ApiError
151
+ ApiError,
125
152
  } from '@atumlabs/payment-gateway-client';
126
- import { ethers } from 'ethers';
127
153
 
128
154
  const client = new PaymentGatewayClient({
129
- BASE: 'https://payment-gateway.atumlabs.xyz' // or your gateway URL
155
+ BASE: 'https://payment-gw.production-testnet.atum.xyz' // or your gateway URL
130
156
  });
131
157
  ```
132
158
 
159
+ ### Gateway URL
160
+
161
+ The client uses the production-testnet gateway by default. To target another
162
+ environment, in order of precedence:
163
+
164
+ 1. Pass it explicitly — SDK `new PaymentGatewayClient({ BASE })`, or the CLI `--gateway` flag.
165
+ 2. Set the `GATEWAY_URL` environment variable.
166
+ 3. Otherwise the built-in default `https://payment-gw.production-testnet.atum.xyz` is used.
167
+
168
+ Mainnet access is granted by Atum; use the mainnet gateway URL provided to you.
169
+
133
170
  ### Example: Tron to Celo Sepolia Payment
134
171
 
135
172
  ```typescript
@@ -149,15 +186,22 @@ async function sendPayment() {
149
186
  fulfillmentAmount: '100000', // 0.10 USDT (6 decimals)
150
187
  sourceAsset: 'tron:shasta/trc20:TG3XXyExBkPp9nzdajDZsozEu4BkaSJozs', // USDT on Tron Shasta
151
188
  destinationAccount: '0xYourEthereumAddressHere',
152
- destinationAsset: 'eip155:11142220/erc20:0x456a3D042C0DbD3db53D5489e98dFb038553B0d0' // USDC on Celo Sepolia
189
+ destinationAsset: 'eip155:11142220/erc20:0x456a3D042C0DbD3db53D5489e98dFb038553B0d0', // USDC on Celo Sepolia
190
+ // Required. Your stable idempotency key — reuse the SAME value on retry so a
191
+ // retry never becomes a second payment (see "Idempotency and retries" below).
192
+ requestId: 'order-4711',
153
193
  });
154
194
 
155
- // Sign the message (Tron uses the same signing as Ethereum, but without the 0x private key prefix)
156
- const wallet = new ethers.Wallet(privateKey.replace(/^0x/, ''));
157
- paymentRequest.sender_auth.signed_messages[0].signature =
158
- wallet.signingKey.sign(
159
- paymentRequest.sender_auth.signed_messages[0].message
160
- ).serialized;
195
+ // Sign the prepared request with the SDK signer helper. It handles the
196
+ // per-chain signing differences internally (EVM typed-data, Tron hash,
197
+ // Solana Ed25519), so you never touch a chain library directly.
198
+ const sourceChainId = 'tron:shasta'; // CAIP-2 chain id, i.e. sourceAsset.split('/')[0]
199
+ const signer = createSenderSigner(sourceChainId, {
200
+ provider: 'raw',
201
+ privateKey,
202
+ pinnedAddress: tronSender,
203
+ });
204
+ await signPaymentRequest(paymentRequest, signer);
161
205
 
162
206
  try {
163
207
  // Submit the payment
@@ -172,9 +216,11 @@ async function sendPayment() {
172
216
 
173
217
  return response;
174
218
  } catch (error) {
175
- if (error instanceof ApiError) {
176
- console.error('API Error:', error.status, error.statusText);
177
- console.error('Response:', error.body);
219
+ const gwError = getErrorResponse(error);
220
+ if (gwError) {
221
+ console.error('Gateway error:', gwError.code, gwError.message, gwError.request_id);
222
+ } else if (error instanceof ApiError) {
223
+ console.error('HTTP', error.status, error.statusText, error.url);
178
224
  }
179
225
  throw error;
180
226
  }
@@ -183,15 +229,29 @@ async function sendPayment() {
183
229
 
184
230
  ### Error Handling
185
231
 
186
- The SDK provides detailed error information through the `ApiError` type:
232
+ The gateway returns a typed, public error body — `ErrorResponse`
233
+ (`{ code, message, request_id?, docs_url?, domain? }`). Use `getErrorResponse`
234
+ to narrow a caught error to it; it returns `undefined` for anything that is not
235
+ a gateway error with that shape. For transport-level detail (HTTP status, URL),
236
+ the thrown value is still an `ApiError`.
187
237
 
188
238
  ```typescript
189
- catch (error) {
190
- if (error instanceof ApiError) {
191
- console.error('Status:', error.status);
192
- console.error('Status Text:', error.statusText);
193
- console.error('URL:', error.url);
194
- console.error('Response Body:', error.body);
239
+ import { getErrorResponse, ApiError } from '@atumlabs/payment-gateway-client';
240
+
241
+ try {
242
+ await client.payments.submitPayment({ requestBody: paymentRequest });
243
+ } catch (error) {
244
+ const gwError = getErrorResponse(error);
245
+ if (gwError) {
246
+ console.error('Code:', gwError.code); // machine-readable category
247
+ console.error('Message:', gwError.message); // safe, human-readable text
248
+ console.error('Request ID:', gwError.request_id); // quote this to support
249
+ console.error('Docs:', gwError.docs_url);
250
+ } else if (error instanceof ApiError) {
251
+ // Transport-level failure with no typed body (e.g. a proxy/gateway error).
252
+ console.error('HTTP', error.status, error.statusText, error.url);
253
+ } else {
254
+ throw error;
195
255
  }
196
256
  }
197
257
  ```
@@ -203,13 +263,29 @@ Assets are identified using the [CAIP-19](https://chainagnostic.org/CAIPs/caip-1
203
263
  - Tron example: `tron:shasta/trc20:TG3XXyExBkPp9nzdajDZsozEu4BkaSJozs`
204
264
  - EVM example: `eip155:11142220/erc20:0x456a3D042C0DbD3db53D5489e98dFb038553B0d0`
205
265
 
206
- ## Package Structure
266
+ ## Idempotency and retries
267
+
268
+ Every payment carries a `request_id`. Pass a stable value and reuse the exact
269
+ same one on every retry (a timeout, a network blip, a restart) and you end up
270
+ with one payment, not two — and you get the same answer each time.
271
+
272
+ - Using this SDK, `request_id` is **required** on the payment path
273
+ (`preparePaymentRequest`), and it is the only thing you manage: the SDK derives
274
+ the on-chain deposit nonce deterministically from it, so retries line up on
275
+ their own. Reuse the same `request_id` to retry safely.
276
+ - On the CLI, `--request-id` is optional; when omitted a one-shot id is generated
277
+ and printed, so you can re-run with `--request-id <id>` to retry the same
278
+ payment.
279
+ - A genuinely new payment needs a **new** `request_id`. Reusing one with different
280
+ terms (a corrected amount, a different token) returns the original payment
281
+ rather than an error, so the new terms are silently dropped.
207
282
 
208
- - `src/` - Source TypeScript files
209
- - `generated/` - Auto-generated API client from OpenAPI spec
210
- - `cli/` - CLI implementation
211
- - `dist/` - Pre-compiled JavaScript (ready to use)
283
+ See [docs/idempotency.md](docs/idempotency.md) for the full model: the two
284
+ guarantees and the per-chain differences (EVM/Tron vs Solana).
212
285
 
213
- ---
286
+ ## What is in the package
214
287
 
215
- This repository contains proprietary Atum Labs code. Access is restricted and governed by the Private Repository License included in this repo.
288
+ - `dist/` — compiled JavaScript and TypeScript declarations, ready to use
289
+ - `dist/cli/` — the four command-line tools
290
+ - `docs/` — reference documentation, including [idempotency and retries](docs/idempotency.md)
291
+ - `LICENSE`, `THIRD-PARTY-NOTICES.txt` — license terms and third-party attribution
@@ -0,0 +1,45 @@
1
+ THIRD-PARTY SOFTWARE NOTICES AND INFORMATION
2
+ ==============================================================================
3
+ @atumlabs/payment-gateway-client
4
+
5
+ The published artifact of this package (the compiled code under dist/) statically
6
+ bundles the third-party open-source components listed below; their source is
7
+ redistributed within this package, so their license and copyright notices are
8
+ reproduced here. Components and versions were taken from the exact modules the
9
+ build inlined. This file does NOT cover packages the consumer installs separately
10
+ as dependencies of this package (for example @solana/web3.js, axios, ethers, bs58,
11
+ commander, dotenv, tweetnacl, and zod) — those ship under their own licenses and are not
12
+ redistributed here.
13
+
14
+ LICENSE SUMMARY (1 component)
15
+ ------------------------------------------------------------------------------
16
+ 1 MIT
17
+ ==============================================================================
18
+
19
+ ------------------------------------------------------------------------------
20
+ @noble/hashes 1.8.0 (MIT)
21
+ Author: Paul Miller (https://paulmillr.com)
22
+ ------------------------------------------------------------------------------
23
+
24
+ The MIT License (MIT)
25
+
26
+ Copyright (c) 2022 Paul Miller (https://paulmillr.com)
27
+
28
+ Permission is hereby granted, free of charge, to any person obtaining a copy
29
+ of this software and associated documentation files (the “Software”), to deal
30
+ in the Software without restriction, including without limitation the rights
31
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
32
+ copies of the Software, and to permit persons to whom the Software is
33
+ furnished to do so, subject to the following conditions:
34
+
35
+ The above copyright notice and this permission notice shall be included in
36
+ all copies or substantial portions of the Software.
37
+
38
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
39
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
40
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
41
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
42
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
43
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
44
+ THE SOFTWARE.
45
+