Atoa CLI
The Atoa CLI is a command-line tool for interacting with the Atoa payment API from your terminal. Create payments, manage customers, test webhooks, and inspect transactions — without leaving the shell, and without writing a script.
It’s the same toolbox the dashboard uses, scriptable for CI/CD, automated test pipelines, support workflows, and one-off operations.
Source code: github.com
Install in seconds
One npm install -g. Works on macOS, Linux, and Windows.
Test webhooks locally
atoa webhooks trigger PAYMENTS_STATUS fires a fake event at your sandbox URL — no real payment needed.
Sandbox & Production
Profiles keep both keys cleanly separated so you never hit production by accident.
Shell completion
TAB-completes commands, flags, profile names, and key IDs across bash, zsh, and PowerShell.
Prerequisites
- Node.js 20 or later — verify with
node --version - An Atoa API Token (sandbox or production) — see the Getting Started guide to generate one
Installation
npm
yarn
pnpm
npm install -g @atoapayments/atoa-cli
Verify the install:
atoa --version
The CLI stores its tokens in your operating system’s keychain (Keychain on
macOS, Credential Manager on Windows, libsecret on Linux). Tokens never
touch a .env file or your shell history.
First-time setup
Pair the CLI with your Atoa account using your API token:
atoa login
You’ll be prompted to:
- Pick an environment —
sandboxorproduction. - Paste your API token
The token is encrypted and stored under a profile named after your business. Subsequent commands authenticate automatically.
Non-interactive login (CI / scripts)
echo "$ATOA_SANDBOX_TOKEN" | atoa login --stdin --env sandbox
Confirm you’re logged in
atoa whoami
✓ business: Acme Ltd
env: sandbox
profile: acme (active)
Environments and profiles
A single machine can hold credentials for many businesses (profiles) and many environments (sandbox + production). The CLI keeps them separate so you can’t accidentally run a production refund while testing locally.
atoa profile list # see every profile and which envs are configured
atoa profile use acme # switch active profile
atoa whoami --env production # check identity for a specific env without switching
When you log in a second time with a production token under the same business:
atoa login --env production
The CLI adds the production credential to the same profile — atoa profile show will show both sandbox and production configured.
Sandbox and production tokens are not interchangeable. The CLI rejects a token at login if its server-reported env doesn’t match the env you picked.
Per-profile settings
CLI state is stored entirely under profiles — there is no separate atoa config command. To change which env a profile defaults to, use atoa profile set. To wipe everything, use atoa reset.
Inspect state
atoa profile list # every profile + which envs each one has
atoa profile show # full metadata for the active profile
atoa profile show acme # metadata for a specific profile
Change the default env on a profile
atoa profile set env=production # active profile; prompts to confirm
atoa profile set env=sandbox --profile acme --yes # scripted / CI
The keys you can set:
| Key | Allowed values | Notes |
|---|---|---|
env | sandbox | production | Sets defaultEnv. Rejected if the profile has no credentials for that env — run atoa login --env <env> first. Prompts for confirmation; pass --yes to skip. |
Reset everything
atoa reset --yes # wipe local profiles + tokens (local only)
atoa reset --revoke --yes # additionally revoke server-side keys (best-effort)
atoa reset is destructive — it removes every profile entry and clears
every keychain slot for this CLI. Use --revoke only when you also want the
server-side keys deactivated (e.g. when offboarding a shared device).
Core workflows
Create a payment
atoa payments create \
--amount 25.00 \
--orderId order-001 \
--customerId cust_123
Returns a paymentRequestId, the customer-facing paymentLink, and a qrCodeUrl.
Check payment status (poll until terminal)
atoa payments status b7c8e3a1-4d29-4f5a-8e6b-1f3a2c4d5e7f --poll
--poll keeps polling every 5 seconds until the status is no longer PENDING, up to 3 minutes.
List recent transactions
atoa payments transactions --from 2026-01-01 --to 2026-01-31 --status COMPLETED
Refund a payment
atoa refunds create \
--paymentRequestId b7c8e3a1-4d29-4f5a-8e6b-1f3a2c4d5e7f \
--amount 5.00 \
--currency GBP \
--notes "duplicate charge" \
--yes
Manage customers and saved cards
atoa customers create --fullName "Jane Doe" --email jane@example.com --type INDIVIDUAL
atoa customers list --search jane
atoa payment-methods list --customer cust_123
atoa card-on-file charge \
--customerId cust_123 \
--paymentMethodId card_456 \
--amount 10.50 \
--orderId order-007
Trigger test webhook events
The most useful feature for local development. The CLI can fire a synthetic webhook payload at your registered sandbox URL — same shape as production — without you actually creating a real payment.
atoa webhooks trigger PAYMENTS_STATUS
Test webhook triggered successfully.
Atoa’s webhook service dispatches the body to whatever sandbox URL you registered with atoa webhooks create. Inspect the request on your endpoint (e.g. webhook.site) to verify your signature-check, routing logic, and response shape work end-to-end.
Supported events
| Event | Body shape |
|---|---|
PAYMENTS_STATUS | Payment-status webhook (pay-by-bank or card) |
REFUND_STATUS | Refund-status webhook |
EXPIRED_STATUS | Payment expired (customer didn’t pay in time) |
POS_PAYMENT_STATUS | POS payment / refund / expired event (select shape via --type) |
Customising the dispatched body
| Flag | Use |
|---|---|
--orderId | Override the orderId in the dispatched payload |
--amount | Override the amount in pounds, e.g. 10.05 for £10.05 |
--paymentMethod | CARD or PAY_BY_BANK |
--status | Force a specific status (COMPLETED, AUTHORIZED, FAILED, CANCELLED, EXPIRED) |
--type | POS_PAYMENT_STATUS only — body shape: PAYMENTS_STATUS (default) | REFUND_STATUS | EXPIRED_STATUS |
--customFields | POS_PAYMENT_STATUS only — JSON array of {value, fieldName} objects |
# Successful card payment
atoa webhooks trigger PAYMENTS_STATUS --paymentMethod CARD --status AUTHORIZED
# Failed pay-by-bank
atoa webhooks trigger PAYMENTS_STATUS --status FAILED
# Refund that failed at the issuer
atoa webhooks trigger REFUND_STATUS --status FAILED
# Custom order ID and amount
atoa webhooks trigger PAYMENTS_STATUS --orderId my-test-order --amount 50.00
# POS_PAYMENT_STATUS has multiple body shapes — pick one via --type
atoa webhooks trigger POS_PAYMENT_STATUS --type PAYMENTS_STATUS
atoa webhooks trigger POS_PAYMENT_STATUS --type REFUND_STATUS --status COMPLETED
atoa webhooks trigger POS_PAYMENT_STATUS --type EXPIRED_STATUS
atoa webhooks trigger POS_PAYMENT_STATUS --type PAYMENTS_STATUS \
--customFields '[{"value":"CUST_001","fieldName":"Customer ID"}]'
Test triggers are sandbox-only by design. If you pass --env production,
the CLI warns on stderr and proceeds with your active profile’s sandbox key
anyway — this prevents accidentally driving fake events at your live customers.
Using the CLI in CI
Every command accepts --output json for machine-readable output and --dryRun for safely previewing requests:
# Preview the request without sending
atoa payments create --amount 10.00 --orderId test --customerId cust_123 --redirectUrl https://paywithatoa.co.uk/ --dryRun
# Skip confirm prompts
atoa refunds create --paymentRequestId b7c8e3a1-4d29-4f5a-8e6b-1f3a2c4d5e7f --amount 5.00 --currency GBP --yes
Generic HTTP verbs
When you need to hit an endpoint the CLI doesn’t yet wrap (or you want full control over the request body), use the raw verbs:
atoa get /api/payments/stores
atoa get /api/customers -d page=0 -d size=20 --pageAll
atoa post /api/webhook/merchant --data @webhook.json
atoa post /api/something -d amount=1005 -d orderId=order-001
atoa delete /api/customers/cust_123 --yes
How -d and --data work
These are two different ways to build the request body. Pick whichever fits the call:
| Form | What it means | Example |
|---|---|---|
-d key=value (repeatable) | Build the body one field at a time. Same flag can be used many times. | -d amount=1005 -d orderId=order-001 |
--data '{"key":"value"}' | Pass the entire body as an inline JSON string. | --data '{"orderId":"o-1","amount":1005}' |
--data @path/to/file.json | The @ prefix means read the body from a file on disk (curl convention). | --data @webhook.json |
--data - | Read the body from stdin (pipe-in form for CI scripts). | cat body.json | atoa post /api/x --data - |
So atoa post /api/webhook/merchant --data @webhook.json reads webhook.json from the directory you ran the command in, takes its contents as the JSON request body, and POSTs it to /api/webhook/merchant. Example file:
// webhook.json
{
"url": "https://your-server.example.com/atoa-hook",
"event": "PAYMENTS_STATUS"
}
-d and --data are mutually meaningful — they both contribute to the same
body. If you pass both, --data wins and -d fields are ignored. Use one or
the other per command.
Passing nested objects and arrays
Some API fields aren’t a single string or number — they’re objects (e.g. authentication, consumerDetails) or arrays (e.g. paymentMethod, storeIds). How you pass these depends on which kind of command you’re using.
-d and --data are flags on the generic verbs only (atoa get, atoa post, atoa delete). Typed commands like atoa payments create and atoa customers create accept only their named flags — they do not accept -d key=value or --data @file.json.
On typed commands (e.g. atoa payments create)
Use the command’s own named flags. Quote complex values so the shell passes them to the CLI intact:
| Value shape | How to pass it | Concrete example |
|---|---|---|
| Object | Inline JSON, single-quoted | --consumerDetails '{"firstName":"Jane","lastName":"Doe","email":"jane@example.com"}' |
| Array (comma form) | Comma-separated string | --paymentMethod CARD,PAY_BY_BANK |
| Multi-value filters | Comma-separated string | --status COMPLETED,FAILED · --storeIds store_uk_1,store_uk_2 |
# Object value via a typed flag (bash / zsh / git-bash)
atoa payments create \
--amount 25.00 --orderId order-001 --customerId cust_123 \
--redirectUrl https://shop.example.com/return \
--consumerDetails '{"firstName":"Jane","lastName":"Doe","email":"jane@example.com","phoneCountryCode":"44","phoneNumber":"7700900000"}'
# Comma-separated array via a typed flag
atoa payments transactions --status COMPLETED,FAILED --storeIds store_uk_1,store_uk_2
PowerShell users: Windows re-parses arguments when handing them to
native .exe / .cmd programs, so the bash-style '{"key":"value"}'
doesn’t survive intact. Use backslash-escaped double quotes inside the
single quotes instead:
# Object value via a typed flag (PowerShell — note the \" escapes)
atoa payments create --amount=25.00 --orderId=order-001 --customerId=cust_123 `
--redirectUrl=https://shop.example.com/return `
--consumerDetails '{\"firstName\":\"Jane\",\"lastName\":\"Doe\",\"email\":\"jane@example.com\",\"phoneCountryCode\":\"44\",\"phoneNumber\":\"7700900000\"}'
If a value contains whitespace (e.g. "Jane Doe"), wrap the whole
backslash-escaped JSON in an extra pair of outer double-quotes so Windows
doesn’t split at the space:
atoa payments create --consumerDetails '"{\"firstName\":\"Jane\",\"lastName\":\"Doe\"}"'
bash / zsh / git-bash users — the single-quoted plain form (top of section) works directly, no escaping needed.
If a typed command doesn’t expose a flag for the field you need, fall through to the generic verbs below.
On generic verbs (e.g. atoa post /api/...)
The generic verbs accept any JSON body. Three ways to specify it:
| Value shape | How to pass it | Concrete example |
|---|---|---|
| Field by field | -d key=value (repeatable) | -d amount=1005 -d orderId=order-001 |
| Object field | -d key=<JSON string> | -d authentication='{"username":"u","password":"p"}' |
| Array field (JSON) | -d key=<JSON array> | -d paymentMethods='["CARD","PAY_BY_BANK"]' |
| Whole body inline | --data '<JSON>' | --data '{"orderId":"o-1","amount":1005}' |
| Whole body from file | --data @path/to/file.json | --data @webhook.json |
| Whole body from stdin | --data - | cat body.json | atoa post /api/x --data - |
# Object value via -d (generic verb)
atoa post /api/webhook/merchant \
-d sandboxUrl=https://example.com/hook \
-d eventTypes=PAYMENTS_STATUS \
-d authentication='{"username":"u","password":"p"}'
# Whole body from a file (generic verb)
atoa post /api/payments/process-payment --data @payment.json
Wrap JSON values in single quotes so {, ", and spaces pass through
untouched.PowerShell: same rule, but escape any inner single quote by
doubling it ('It''s urgent' → It's urgent).
These use your active profile’s credentials and respect every common flag (--env, --output, --dryRun, --verbose). Useful for:
- New endpoints that haven’t gained a typed wrapper yet
- Debugging —
--verboseprints the redacted request line so you can diff againstcurl - CI scripts where you want explicit control over the exact body sent
Shell completion
Enable TAB-completion of commands, flags, profile names, and IDs:
bash
zsh
PowerShell
atoa completion bash >> ~/.bashrc && source ~/.bashrc
After installing, hit <TAB> mid-command:
atoa pa<TAB> → payments, payment-methods, payouts
atoa payments <TAB> → create, status, cancel, transactions
atoa profile use <TAB> → live profile names from your config
Command reference
Most commands accept these common flags (per-command --help is authoritative):
| Flag | Use |
|---|---|
--env | Override env (sandbox | production) for this single command |
--output | json | table | yaml |
--verbose | Print redacted request log to stderr |
--dryRun | Resolve the request but don’t send it |
--yes | Skip confirmation prompts |
--profile | Operate against a specific profile |
Troubleshooting
Need Help?
Contact our team at hello@paywithatoa.co.uk or use chat support on the Dashboard.