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


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:

  1. Pick an environmentsandbox or production.
  2. 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:

KeyAllowed valuesNotes
envsandbox | productionSets 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

EventBody shape
PAYMENTS_STATUSPayment-status webhook (pay-by-bank or card)
REFUND_STATUSRefund-status webhook
EXPIRED_STATUSPayment expired (customer didn’t pay in time)
POS_PAYMENT_STATUSPOS payment / refund / expired event (select shape via --type)

Customising the dispatched body

FlagUse
--orderIdOverride the orderId in the dispatched payload
--amountOverride the amount in pounds, e.g. 10.05 for £10.05
--paymentMethodCARD or PAY_BY_BANK
--statusForce a specific status (COMPLETED, AUTHORIZED, FAILED, CANCELLED, EXPIRED)
--typePOS_PAYMENT_STATUS only — body shape: PAYMENTS_STATUS (default) | REFUND_STATUS | EXPIRED_STATUS
--customFieldsPOS_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:

FormWhat it meansExample
-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.jsonThe @ 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 shapeHow to pass itConcrete example
ObjectInline 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 filtersComma-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 shapeHow to pass itConcrete 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--verbose prints the redacted request line so you can diff against curl
  • 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):

FlagUse
--envOverride env (sandbox | production) for this single command
--outputjson | table | yaml
--verbosePrint redacted request log to stderr
--dryRunResolve the request but don’t send it
--yesSkip confirmation prompts
--profileOperate against a specific profile

Troubleshooting


Need Help?

Contact our team at hello@paywithatoa.co.uk or use chat support on the Dashboard.