Reference
CLI Reference
eIOU CLI Reference
Complete command-line interface documentation for the eIOU Docker node.
Table of Contents
- Overview
- Global Options
- Wallet Commands
- Contact Commands
- Transaction Commands
- Dead Letter Queue
- Settings Commands
- System Commands
- API Key Management
- Payback Methods
- Payment Request Commands
- Tx Drop Commands
- Backup Commands
- Export Commands
- Chain Integrity Audit
- Plugin Management
- Report Commands
- Test Mode Commands
- Exit Codes
- Rate Limiting
Overview
The eIOU CLI provides a command-line interface for interacting with an eIOU wallet node.
Note: All examples in this reference show bare
eioucommands as run inside the container. From the host machine, prependdocker exec <container>:docker exec eiou-node eiou info # from the host eiou info # inside the container (docker exec -it <container> bash)
Usage:
eiou <command> [arguments] [options]
All commands support JSON output mode for scripting and automation.
Global Options
These options are available for all commands:
| Option | Description |
|---|---|
--json, -j |
Output results in JSON format for scripting/automation |
--no-metadata |
Exclude metadata (timestamp, node_id) from JSON output |
Example:
eiou info --json
eiou viewbalances -j --no-metadata
JSON Output Structure
When using --json, all commands return a consistent response format:
{
"success": true,
"data": {
// Command-specific response data
},
"metadata": {
"timestamp": "2026-01-24T17:45:00Z",
"node_id": "http://alice",
"command": "viewbalances"
}
}
| Field | Type | Description |
|---|---|---|
success |
boolean | Whether the command executed successfully |
data |
object | Command-specific response data |
metadata |
object | Request metadata (excluded with --no-metadata) |
metadata.timestamp |
string | ISO 8601 timestamp of the response |
metadata.node_id |
string | Node identifier (hostname/address) |
metadata.command |
string | The command that was executed |
Error Response:
{
"success": false,
"error": {
"code": "INSUFFICIENT_BALANCE",
"message": "Insufficient funds for this transaction"
}
}
Wallet Commands
generate (startup only)
Wallet generation and restoration are handled automatically by startup.sh during container initialization. By the time the CLI is accessible, a wallet already exists, so running eiou generate will always return a “wallet already exists” error.
Wallet creation is configured via Docker environment variables:
| Variable | Description |
|---|---|
EIOU_HOST |
Hostname (IP, FQDN, or bare hostname for Docker-network use; optional :port to advertise a non-default port to peers). Setting this enables HTTP/HTTPS mode. Omit for Tor-only |
EIOU_NAME |
Display name for the node (defaults to EIOU_HOST) |
EIOU_PORT |
Externally-published HTTPS port for nginx redirect targets, SSL cert CN, and the eiou info browser-display URL. Does NOT enter the wallet locator peers receive — for a non-default port in the locator, embed it in EIOU_HOST or run eiou changesettings hostname https://host:port |
RESTORE |
BIP39 seed phrase (24 words) to restore an existing wallet |
RESTORE_FILE |
Path to file containing seed phrase (recommended — more secure) |
Restoring contacts from a prior wallet:
After restoring a wallet from a seed phrase, your previous contacts are not immediately present. When a prior contact pings or sends a message to your restored node, the ContactStatusService automatically creates a pending contact entry and triggers a sync to restore the shared transaction chain. The restored contact appears as a pending request (visible via eiou contact pending) that you can re-accept with eiou contact accept <pubkey-hash> --currency CCY --fee F --credit C (or eiou contact apply for multi-currency). If autoAcceptRestoredContact is enabled, the original per-currency settings are auto-restored and no manual accept is needed.
info
Display wallet information including addresses, public key, fee earnings, and available credit.
Syntax:
eiou info [detail] [--show-auth]
Arguments:
| Argument | Type | Description |
|---|---|---|
detail |
optional | Show detailed balance information with transaction breakdowns |
--show-auth |
optional | Securely display the authentication code via temp file |
Examples:
# Basic wallet info (auth code redacted)
eiou info
# Show authentication code securely
eiou info --show-auth
# Detailed info with balances
eiou info detail
# JSON output with auth code file path
eiou info --show-auth --json
Output includes:
- HTTP, HTTPS, and Tor addresses (locators)
- Authentication code status (redacted by default)
- Public key
- Total fee earnings per currency (P2P relay fee earnings)
- Total available credit per currency (sum of credit available through all contacts, received via ping/pong)
- (With
detail) Total balances by currency with sent/received breakdown
Security: Authentication Code Handling
The authentication code is a sensitive credential that is never exposed directly in command output. This prevents accidental exposure through:
- Docker logs (
docker logs <container>) - Shell history and command output redirection
- Log aggregation systems
- Screenshots or screen sharing
When --show-auth is used, the code is stored in a secure temporary file:
- TTY Mode (interactive terminal): Displays directly to terminal, bypassing Docker’s log capture
- Non-TTY/JSON Mode: Stores in
/dev/shm/(memory-only tmpfs) with auto-deletion after 5 minutes
Retrieving the authentication code:
# The command outputs the file path
docker exec alice eiou info --show-auth
# Then retrieve it manually
docker exec alice cat /dev/shm/eiou_authcode_<random>
# Delete after use (or wait for auto-deletion)
docker exec alice rm /dev/shm/eiou_authcode_<random>
JSON response format with --show-auth:
{
"authentication_code": {
"status": "stored_securely",
"method": "file",
"filepath": "/dev/shm/eiou_authcode_abc123...",
"ttl_seconds": 300,
"message": "Authentication code stored in secure temp file"
}
}
overview
Display a dashboard summary with balances and recent transactions.
Syntax:
eiou overview [limit]
Arguments:
| Argument | Type | Default | Description |
|---|---|---|---|
limit |
optional | 5 | Number of recent transactions to display |
Examples:
# Default overview (5 recent transactions)
eiou overview
# Show 10 recent transactions
eiou overview 10
# JSON output
eiou overview --json
Contact Commands
All contact operations are namespaced under eiou contact …. Identifiers (<contact>) accept a name, an address, or a pubkey-hash — pipe scripted values from eiou contact pending --json for stable identifiers across runs. Top-level verbs (eiou add, eiou pending, eiou block, …) were dropped in v0.1.14 in favour of subcommands so the apply / decline / per-currency surfaces have a home and identifier parsing is consistent.
Rate limit: 20 contact ops per minute (contact rate-limit bucket).
contact add
Initiate an outbound contact request. Outbound-only — for an existing accepted contact use contact currency add to propose a new currency, or contact update to change settings.
eiou contact add <address> <name> [--fee F --credit C --currency CCY] [--requested-credit RC [--enforce-requested-credit]] [--message M]
| Flag | Default | Description |
|---|---|---|
--fee |
0 |
Fee percentage you’ll charge to relay transactions in this currency. |
--credit |
0 |
Credit limit you extend to this contact in this currency. 0 means contact-only (no transactions can route through you). |
--currency |
VWL |
Currency code (3-10 alphanumeric, case-insensitive; fiat normalized to uppercase, e.g. VWL, EIOU). |
--requested-credit |
— | Credit limit you’d like the receiver to extend to you in this currency. Sent on the wire as requested_credit_limit in the contact payload — the receiver sees it as a suggestion when they accept (mirrors what the GUI’s “Requested Credit” field and the POST /api/v1/contacts endpoint expose). They choose what to actually grant. Omit to send no suggestion. |
--enforce-requested-credit |
off | Treat --requested-credit as a hard minimum: the receiver may grant more but not less, and their wallet refuses to accept while granting less (a clear per-currency error). Only meaningful alongside --requested-credit. The credit a contact extends is their own local setting, so this is enforced by the receiver’s wallet (and is exposed to API clients), not cryptographically imposed. |
--message |
— | Optional short message (≤ 255 chars, E2E or transport-encrypted). |
Flags can appear in any order, and in any position relative to the positional <address> <name>.
# Contact request with all defaults
eiou contact add http://bob:8080 Bob
# With explicit per-currency settings + a message
eiou contact add http://bob:8080 Bob --fee 1.0 --credit 100 --currency VWL --message "Hey, it's Dave!"
# Suggest that Bob extend you a 500 VWL credit limit when he accepts
eiou contact add http://bob:8080 Bob --fee 1.0 --credit 100 --currency VWL --requested-credit 500
# Require at least 500 VWL: Bob can grant more, but his wallet won't let him accept with less
eiou contact add http://bob:8080 Bob --fee 1.0 --credit 100 --currency VWL --requested-credit 500 --enforce-requested-credit
# Multi-word names need quoting in your shell — there's no special placeholder
eiou contact add http://bob:8080 "Jane Doe" --fee 1.0 --credit 100 --currency VWL
contact accept
Accept an incoming contact request from the receiving side. Single- or multi-currency in one shot — repeat the --currency / --fee / --credit triplet per currency.
eiou contact accept <pubkey-hash|address|name> --currency CCY --fee F --credit C \
[--currency CCY --fee F --credit C ...]
# Single-currency accept
eiou contact accept abc123...hash --currency VWL --fee 1.0 --credit 100
# Multi-currency accept in one call
eiou contact accept abc123...hash \
--currency VWL --fee 1.0 --credit 100 \
--currency EUR --fee 0.5 --credit 50
For new (pending) contacts, the first accepted currency establishes the contact via the same path as contact add; subsequent accepts use the standard currency-acceptance path. This mirrors what the GUI batched-apply modal does and is implemented by the shared ContactDecisionService::apply().
contact apply
Apply a batched mix of accept / decline / defer decisions in one call — the CLI mirror of the GUI batched-apply modal. Two payload forms:
# Per-decision flags (repeatable)
eiou contact apply <pubkey-hash|address|name> [--accept CCY:fee:credit ...] \
[--decline CCY ...] [--defer CCY ...]
# Or pipe a JSON array (modal payload shape: [{currency, action, fee?, credit?}, ...])
eiou contact apply <pubkey-hash|address|name> --from <file.json|->
# Accept VWL, decline EUR, defer XRP
eiou contact apply abc123...hash --accept VWL:0.01:1000 --decline EUR --defer XRP
# Pipe modal output through a script
cat decisions.json | eiou contact apply abc123...hash --from -
Declines run before accepts so a decline EUR + accept VWL payload can’t accidentally re-add the just-declined row via the new-contact bridge. Defer rows are intentional no-ops.
contact decline
Decline every pending currency on a contact request in one shot.
eiou contact decline <pubkey-hash|address|name>
Each declined currency triggers a contact_currency_declined notification to the requester so their outgoing-pending row is dropped on the spot — without it the requester’s view of the request hangs forever and a retry trips the legacy CONTACT_EXISTS path. After all per-currency declines, a single contact_declined notification is sent so the requester’s contact transaction itself is rejected. Both message types are async-best-effort and fall back to DLQ retries on transport failure; the next ping/pong cycle reconciles any drift via peerKnownCurrencies (see eiou contact ping below).
contact list
List contacts grouped by status.
eiou contact list [--status accepted|pending|blocked]
contact pending
View pending contact requests (incoming + outgoing). The hint text printed for each incoming request points at eiou contact accept <pubkey-hash> … and eiou contact decline <pubkey-hash> so the printed command is paste-ready.
eiou contact pending [--json]
After a wallet restore, prior contacts that ping your node are auto-created as pending requests by ContactStatusService and appear here. They can be re-accepted via contact accept (or contact apply for multi-currency).
contact view
View detailed information about a contact.
eiou contact view <name|address|pubkey-hash>
Output includes name, status, addresses, per-currency balances, fee/credit-limit settings, and your / their available credit per currency (refreshed via the ping/pong cycle, ~5 min).
contact update
Update contact settings via flags — same shape as contact add, mirrors the API’s PUT /api/v1/contacts/:address payload. All field flags are optional; provide whichever subset you want to change.
eiou contact update <name|address> [--name N] [--fee F] [--credit C] [--currency CCY]
| Flag | Required when | Description |
|---|---|---|
--name |
— | New display name (currency-independent). |
--fee |
always paired with --currency |
New fee percentage in the given currency. |
--credit |
always paired with --currency |
New credit limit in the given currency. |
--currency |
when --fee or --credit is set |
Currency code for the per-currency row being updated. |
# Rename
eiou contact update Bob --name Robert
# Change fee on an existing currency
eiou contact update Bob --fee 1.5 --currency VWL
# Change credit limit
eiou contact update Bob --credit 500 --currency EUR
# Multi-field — name + fee + credit in one command
eiou contact update Bob --name Robert --fee 2.0 --credit 1500 --currency VWL
# By address
eiou contact update http://bob --fee 2.0 --currency VWL --json
Atomicity: the CLI fans out into one service call per touched field (
name,fee,credit), so a multi-field update is not atomic across the name/per-currency boundary. The API equivalent (PUT /api/v1/contacts/:address) is atomic per request — use it if you need transactional semantics. Updates are local-only either way (the contact is not notified).
Breaking change (v0.1.14): the legacy positional form (
eiou contact update Bob name Robert/… fee 1.5 VWL/… all Robert 1.5 1500 VWL) was removed in favour of this flag form. Scripts using the old grammar will fail with a “No fields to update” or “Usage” error.
contact delete / block / unblock / ping / search
eiou contact delete <name|address> # Permanent removal
eiou contact block <name|address> # Reject incoming traffic from this contact
eiou contact unblock <name|address> # Reverse a prior block
eiou contact ping <name|address> # Check online status + per-currency chain heads
eiou contact search <query> # Substring search by name
contact ping compares per-currency chain heads with the remote contact and verifies local chain integrity (gap detection). Mismatches trigger an automatic sync; if the sync can’t repair the gap, a tx drop is auto-proposed (see Tx Drop Commands). All gap detection is local — no transaction lists go over the wire.
contact currency add
Propose a new currency on an already-accepted contact. Sends a P2P request so the remote side can accept the new currency.
eiou contact currency add <contact> <currency> --fee F --credit C
contact currency accept / decline
Accept or decline a single per-currency request that’s pending on an existing contact. The accept path runs through ContactDecisionService so it shares the new-contact-first-accept-via-add semantics with the GUI modal.
eiou contact currency accept <contact> <currency> --fee F --credit C
eiou contact currency decline <contact> <currency>
decline sends a contact_currency_declined notification to the requester (best-effort, async). The remote drops their stale outgoing-pending row immediately on receipt; if the message is lost in flight, the next ping/pong call reconciles it via the peerKnownCurrencies payload field. A retry by the requester (contact currency add) succeeds in either case — the dispatcher detects a stale outgoing-pending row and routes it through addCurrencyToExisting instead of bailing with CONTACT_EXISTS.
contact currency list
Show every currency configured for a contact, with status (pending / accepted / declined) and direction (incoming / outgoing).
eiou contact currency list <contact>
contact currency remove
Remove a currency configuration locally. Local-only — the remote side is not notified. Use this to clean up a stale outgoing pending request, not to reject one (use currency decline for that).
eiou contact currency remove <contact> <currency>
p2p
Manage P2P transactions awaiting manual approval. Used when autoAcceptTransaction is disabled.
Syntax:
eiou p2p [subcommand] [args...]
Subcommands:
| Subcommand | Syntax | Description |
|---|---|---|
| (none/list) | eiou p2p |
List all P2P transactions awaiting approval |
candidates |
eiou p2p candidates <hash> |
Show route candidates for a transaction |
approve |
eiou p2p approve <hash> [index] |
Approve and send a P2P transaction |
reject |
eiou p2p reject <hash> |
Reject and cancel a P2P transaction |
Examples:
# List pending P2P transactions
eiou p2p
eiou p2p --json
# View route candidates for a transaction
eiou p2p candidates abc123def456
# Approve a single-route P2P (fast mode)
eiou p2p approve abc123def456
# Approve using a specific candidate route (best-fee mode)
eiou p2p approve abc123def456 2
# Reject and cancel a P2P transaction
eiou p2p reject abc123def456
Output includes:
- Transaction hash, amount, currency
- Route mode (fast or best-fee)
- Number of route candidates
- Total cost including relay fees
Approval behavior:
- Fast mode (single route):
eiou p2p approve <hash>sends immediately - Best-fee mode (multiple candidates): Use
eiou p2p candidates <hash>to view options, theneiou p2p approve <hash> <index>to select a route - If multiple candidates exist but no index is provided, an error is returned
Routing mode scenarios:
| Routing Mode | autoAcceptTransaction |
What Happens |
|---|---|---|
| Fast (default) | ON (default) | Route is auto-sent — no approval needed |
| Fast | OFF | 1 route shown, use eiou p2p approve <hash> |
Best-fee (--best) |
ON | Cheapest route is auto-sent — no approval needed |
| Best-fee | OFF | All routes listed, use eiou p2p candidates <hash> then eiou p2p approve <hash> <index> |
| Best-fee + Tor dest | OFF | Internally fast mode — 1 route shown, use eiou p2p approve <hash> |
Notes:
- P2P transactions enter
awaiting_approvalstatus whenautoAcceptTransactionisfalse. Without these commands (or GUI/API equivalents), such transactions expire through normal cleanup. - Late-arriving route candidates are still accepted while a transaction is awaiting approval and will appear in the candidate list.
- Tor destinations force fast mode internally because Tor hidden services use single-hop routing.
Dead Letter Queue
dlq
Manage the dead letter queue (DLQ) — messages that could not be delivered after all automatic retry attempts.
Syntax:
eiou dlq [subcommand] [id] [--status=<filter>]
Subcommands:
| Subcommand | Syntax | Description |
|---|---|---|
| (none/list) | eiou dlq |
List active (pending + retrying) DLQ items |
list |
eiou dlq list [--status=all] |
List items with optional status filter |
retry |
eiou dlq retry <id> |
Retry delivering a failed message |
abandon |
eiou dlq abandon <id> |
Mark an item as abandoned (no further retries) |
Status filter values for --status:
| Value | Description |
|---|---|
| (omitted) | Active items: pending + retrying (default) |
pending |
Awaiting manual action |
retrying |
Currently being retried |
resolved |
Successfully re-delivered |
abandoned |
Manually discarded |
all |
All items regardless of status |
Examples:
# List active DLQ items (pending + retrying)
eiou dlq
# List all items including resolved and abandoned
eiou dlq list --status=all
# List only pending items
eiou dlq list --status=pending
# Retry a specific item (transaction or contact only)
eiou dlq retry 42
# Abandon an item (cannot be undone)
eiou dlq abandon 42
# JSON output with statistics
eiou dlq --json
Output includes:
- Item ID, message type, status, retry count
- Recipient address
- Failure reason
- Timestamp when added
DLQ Message Types and Retry Eligibility
Important: Not all message types can be meaningfully retried. The DLQ captures messages from this node only — all items represent outbound messages that this node tried to send.
| Type | Description | Can Retry? | Reason |
|---|---|---|---|
transaction |
Direct eIOU payment to a contact | ✅ Yes | User-initiated; payload is refreshed against the current chain head before each retry (see below) |
contact |
Contact request sent to a peer | ✅ Yes | User-initiated; contact request remains valid |
p2p |
P2P routing request forwarded to a peer | ❌ No | Time-sensitive; expires in ≤300s — stale by the time retries are exhausted |
rp2p |
Relay response/cancel forwarded through this node | ❌ No | Relay message on behalf of others; underlying P2P transaction has expired or been resolved elsewhere |
Transaction payload refresh on retry: A transaction can sit in the DLQ for
minutes to hours. In that window the local chain may have advanced (new
outbound txs) or had a tx drop re-wire the link past a missing
transaction. On every retry — whether from
eiou dlq retry, the GUI’s Retry button, or the automatic retry queue — the
payload’s previousTxid and time are refreshed from current DB state before
the send. The transport layer re-signs the envelope on that send, and after a
successful delivery the fresh signature and nonce are persisted back to the
transactions table so later chain sync responses serve a signature that
still verifies.
Why p2p and rp2p cannot be retried:
P2P and relay messages carry an expiration timestamp. Automatic retries use exponential backoff (2s, 4s, 8s, 16s, 32s = ~62s minimum). The default P2P expiration is 300 seconds. By the time automatic retries are exhausted and the message reaches the DLQ, the P2P handshake on all other nodes has already timed out or been resolved through a different route.
Retrying a stale rp2p relay message could deliver a response for a transaction the originating node has already cancelled or completed — causing confusion or double-processing on the recipient.
Recommended action for p2p/rp2p DLQ items: Use eiou dlq abandon <id> to clear them. The original sender’s P2P transaction will have already triggered its own timeout and cleanup.
Automatic lifecycle:
- Messages enter the DLQ after
DELIVERY_MAX_RETRIES(5) failed delivery attempts - Resolved and abandoned records are automatically deleted after
cleanupDlqRetentionDays(default: 90 days) - The GUI shows a warning toast and a Failed Messages badge in Quick Actions whenever pending items exist
Transaction Commands
send
Send an eIOU transaction to a contact.
Syntax:
eiou send <address|name> <amount> <currency> [description] [--best]
Arguments:
| Argument | Type | Description |
|---|---|---|
address|name |
required | Recipient’s address or display name |
amount |
required | Amount to send (positive number) |
currency |
required | Currency code, 3-10 alphanumeric characters (case-insensitive; fiat normalized to uppercase) (e.g., VWL, EIOU) |
description |
optional | Transaction description/memo text |
Flags:
| Flag | Description |
|---|---|
--best |
[EXPERIMENTAL] Use best-fee routing. Collects all P2P route responses and selects the one with the lowest accumulated fee. This feature is experimental and may be slower or less reliable than the default fast mode. Ignored for Tor recipients (.onion addresses) — fast mode is always used over Tor to avoid excessive relay overhead. |
Examples:
# Send by contact name (fast mode, default)
eiou send Bob 50 VWL
# Send by address
eiou send http://bob:8080 100 VWL
# Send with a description
eiou send Bob 50 VWL "Payment for lunch"
# Send with best-fee routing (experimental)
eiou send Bob 50 VWL --best
# Send with description and best-fee routing
eiou send Bob 50 VWL "Invoice #123" --best
# JSON output
eiou send Alice 25.50 VWL --json
Notes:
- Transaction may be direct or routed through intermediaries (P2P relay)
- Default routing uses fast mode: the first RP2P response wins (lowest latency)
- With
--best, all RP2P responses are collected and the lowest-fee route is selected (higher latency, lower cost) - Chain integrity is verified locally before every send; if a gap is detected, sync is attempted and then a tx drop is auto-proposed if the gap persists
- Rate limited: 30 transactions per minute
Transport selection:
The transport used to deliver the transaction is determined by how the recipient is specified:
| Recipient form | Example | Transport used |
|---|---|---|
| Explicit address with scheme | eiou send http://Bob 100 VWL |
HTTP (scheme taken from address) |
| Explicit address with scheme | eiou send https://Bob 100 VWL |
HTTPS |
| Explicit address with scheme | eiou send Bob.onion 100 VWL |
Tor |
| Contact name (no scheme) | eiou send Bob 100 VWL |
defaultTransportMode setting (default: tor) |
When you pass a full address like http://Bob, the scheme is extracted and used directly. When you pass a contact name, no transport is implied so the wallet falls back to the defaultTransportMode setting (configurable via eiou changesettings defaultTransportMode). This is intentional: the two forms are equivalent in who receives the transaction, but differ in how it is delivered.
On Failure (JSON):
Contact not found:
{
"success": false,
"error": {
"code": "NO_CONTACTS",
"title": "No Contacts Available",
"status": 400,
"detail": "No contacts available for transaction",
"recipient": "http://unknown:8080",
"amount": 50,
"currency": "VWL"
}
}
Insufficient balance:
{
"success": false,
"error": {
"code": "INSUFFICIENT_FUNDS",
"title": "Insufficient Funds",
"status": 403,
"detail": "Insufficient balance for this transaction"
}
}
refund
Return a previously-received transaction to its original sender, in full or in part. You name only the received txid; the recipient (the original sender) and the currency are taken from the wallet’s own stored record, and the amount is capped at what was actually received, so a refund cannot be redirected, re-priced, or inflated.
Syntax:
eiou refund <txid> [amount]
Arguments:
| Argument | Type | Description |
|---|---|---|
txid |
required | The txid of a received transaction to return |
amount |
optional | Amount to return. Omit to return the full remaining; a smaller value makes a partial refund. |
Examples:
# Return the full remaining amount to whoever sent it
eiou refund 3f2a9c...
# Return part of it (a partial refund of 5)
eiou refund 3f2a9c... 5
# JSON output
eiou refund 3f2a9c... --json
Notes:
- Only inbound, settled (received) transactions are eligible, and the funds always go back to the original sender.
- The amount defaults to the full remaining. A transaction can be returned in several partial refunds over time, capped so the total returned never exceeds the amount received; an in-flight refund counts toward the cap.
- Each refund is an ordinary outgoing transaction. When it routes over P2P, the return-routing fee is paid on top, from your balance; the original inbound fees the sender paid are sunk and cannot be recovered.
- The same operation is available in the wallet GUI (“Return to sender” on a received transaction’s detail), over REST (
POST /api/v1/wallet/refund), and to allow-listed plugins (wallet_refund_return_to_sender). - Rate limited: 20 refunds per minute.
On Success (JSON):
{
"success": true,
"data": {
"ok": true,
"original_txid": "3f2a9c...",
"refund_txid": "8b1d4e...",
"amount": "5",
"currency": "VWL",
"original_amount": "50",
"already_refunded": "0",
"remaining": "45",
"fully_refunded": false
}
}
On Failure (JSON):
Not a received transaction, amount over the refundable cap, or already fully refunded:
{
"success": false,
"error": {
"code": "INVALID_PARAMS",
"status": 400,
"detail": "Amount exceeds the refundable remainder for this transaction"
}
}
viewbalances
View eIOU balances with all contacts or a specific contact.
Syntax:
eiou viewbalances [address|name]
Arguments:
| Argument | Type | Description |
|---|---|---|
address|name |
optional | Filter by specific contact |
Examples:
# View all balances
eiou viewbalances
# View balance with specific contact
eiou viewbalances Bob
# JSON output
eiou viewbalances --json
history
View transaction history with all contacts or a specific contact. Output is capped by the maxOutput setting (default: 5 lines) unless overridden with a limit argument.
Syntax:
eiou history [address|name] [limit]
Arguments:
| Argument | Type | Description |
|---|---|---|
address|name |
optional | Filter by specific contact |
limit |
optional | Maximum transactions to display (0 = unlimited) |
Examples:
# View all transaction history
eiou history
# View history with specific contact
eiou history Bob
# View all history with Bob (no limit)
eiou history Bob 0
# JSON output
eiou history --json
Settings Commands
viewsettings
Display current wallet settings.
Syntax:
eiou viewsettings
Examples:
eiou viewsettings
eiou viewsettings --json
Settings displayed (grouped by category):
- Transaction Settings: Default currency, minimum/default/maximum fee percentages, default credit limit
- P2P & Network: Max P2P level, P2P expiration, direct TX delivery expiration, default transport mode, HTTP/Tor transport timeouts, hostname (HTTP and HTTPS), trusted proxies, auto-accept P2P transactions
- Feature Toggles: Display name, auto-refresh, contact status pinging, contact status sync on ping, auto tx drop propose/accept, API enabled, API CORS origins, rate limiting
- Backup & Logging: Auto-backup, backup retention count, backup schedule, log level, log max entries
- Data Retention: Delivery, DLQ, held TX, RP2P, metrics retention days
- Rate Limiting: P2P rate limit per minute, max attempts, window, block duration
- Display: Max output lines (displays “unlimited” when set to 0), date format, currency decimals, recent transactions limit
- Currency Management: Allowed currencies
changesettings
Change wallet settings.
Syntax:
eiou changesettings [setting] [value]
Arguments:
| Argument | Type | Description |
|---|---|---|
setting |
optional | Setting name to change (interactive mode if omitted) |
value |
optional | New value for the setting |
Available Settings:
| Setting | Description | Example Value |
|---|---|---|
defaultFee |
Default routing fee percentage (default 0 = no fee; set non-zero to charge new contacts) |
0 |
defaultCreditLimit |
Default credit limit for new contacts | 100 |
defaultCurrency |
Default currency code | VWL |
minFee |
Minimum fee floor (default 0 = free; set non-zero to cover routing costs on tiny transfers) |
0 |
maxFee |
Maximum fee percentage | 5.0 |
maxP2pLevel |
Maximum P2P routing hops | 3 |
p2pExpiration |
P2P routing request timeout (seconds); P2P transactions get an extra 120s delivery window after this expires | 300 |
directTxExpiration |
Direct (non-P2P) transaction delivery timeout in seconds; 0 = no expiry (default); recommended: 120 (two Tor round-trips) |
0 |
maxOutput |
Max display lines (0 = unlimited) | 50 |
defaultTransportMode |
Preferred transport | http, https, tor |
autoBackupEnabled |
Auto-backup database daily | true, false |
analyticsEnabled |
Share anonymous usage statistics (opt-in) | true, false |
autoAcceptTransaction |
Auto-accept P2P transactions when route found | true, false |
hostname |
Node locator URL — sets both hostname (HTTP form) and hostname_secure (HTTPS form), regenerates the SSL cert. Pass either form; the complementary form is derived. The port is preserved on the form you typed and stripped from the derived form (e.g. https://host:9443 becomes hostname_secure=https://host:9443 plus hostname=http://host, because the HTTPS port is not the HTTP port). To carry a port on both schemes, run the command twice with the two forms |
http://alice, https://host:9443 |
name |
Display name for this node | Alice |
trustedProxies |
Trusted proxy IPs or narrow CIDRs for header forwarding; overly broad ranges are rejected | 10.0.0.1,172.16.0.0/12 |
allowedCurrencies |
Allowed currencies (comma-separated) | VWL,EUR |
autoRejectUnknownCurrency |
Auto-reject contact requests with currencies not in your allowed list | true, false |
Advanced Settings (Feature Toggles):
| Setting | Description | Example Value |
|---|---|---|
hopBudgetRandomized |
Randomize P2P hop depth for privacy (disable for max reachability in sparse networks) | true, false |
contactStatusEnabled |
Enable contact status tracking | true, false |
contactStatusSyncOnPing |
Sync status during ping operations | true, false |
autoChainDropPropose |
Auto-propose tx-drop operations | true, false |
autoChainDropAccept |
Auto-accept tx-drop proposals | true, false |
autoChainDropAcceptGuard |
Balance guard for auto-accept tx drops | true, false |
autoAcceptRestoredContact |
Auto-accept restored contacts on wallet restore | true, false |
apiEnabled |
Enable REST API endpoint | true, false |
apiCorsAllowedOrigins |
Allowed CORS origins for API | https://example.com |
rateLimitEnabled |
Enable rate limiting (CLI/API only — not exposed in GUI) | true, false |
Advanced Settings (Backup & Logging):
| Setting | Description | Example Value |
|---|---|---|
backupRetentionCount |
Number of backup files to keep (min 1) | 3 |
backupCronHour |
Backup schedule hour UTC (0-23) | 0 |
backupCronMinute |
Backup schedule minute (0-59) | 0 |
logLevel |
Minimum log level | DEBUG, INFO, WARNING, ERROR, CRITICAL |
logMaxEntries |
Max log entries to keep (min 10) | 100 |
Advanced Settings (Data Retention):
| Setting | Description | Example Value |
|---|---|---|
cleanupDeliveryRetentionDays |
Days to retain delivery records (min 1) | 30 |
cleanupDlqRetentionDays |
Days to retain dead letter queue entries (min 1) | 90 |
cleanupHeldTxRetentionDays |
Days to retain held transactions (min 1) | 7 |
cleanupRp2pRetentionDays |
Days to retain P2P routing records (min 1) | 30 |
cleanupMetricsRetentionDays |
Days to retain metrics data (min 1) | 90 |
paymentRequestsArchiveRetentionDays |
Days resolved (non-pending) payment requests stay in the live table before moving to payment_requests_archive (min 1). Not a delete — archived rows stay queryable |
180 |
paymentRequestsArchiveBatchSize |
Max rows moved per archival cron run (min 1) | 500 |
transactionsArchiveRetentionDays |
Days completed transactions stay in the live table before moving to transactions_archive (min 1). Archival is additionally gated per bilateral pair on a gap-free chain-integrity check — pairs with a detected gap are skipped, not archived. Not a delete |
30 |
transactionsArchiveBatchSize |
Max rows moved per transactions archival cron run (min 1) | 500 |
Advanced Settings (Rate Limiting):
| Setting | Description | Example Value |
|---|---|---|
p2pRateLimitPerMinute |
Max P2P requests per minute (min 1) | 60 |
rateLimitMaxAttempts |
Max attempts before rate limit triggers (min 1) | 10 |
rateLimitWindowSeconds |
Rate limit time window in seconds (min 1) | 60 |
rateLimitBlockSeconds |
Block duration after limit exceeded (min 1) | 300 |
Advanced Settings (Network):
| Setting | Description | Example Value |
|---|---|---|
httpTransportTimeoutSeconds |
HTTP transport timeout (5-120) | 15 |
torTransportTimeoutSeconds |
Tor transport timeout (10-300) | 30 |
torCircuitMaxFailures |
Consecutive Tor failures before cooldown (1-10) | 3 |
torCircuitCooldownSeconds |
Cooldown duration after max failures (60-3600) | 300 |
torFailureTransportFallback |
Fall back to HTTP/HTTPS when Tor fails | true, false |
torFallbackRequireEncrypted |
Only fall back to HTTPS, never plain HTTP | true, false |
Advanced Settings (Display):
| Setting | Description | Example Value |
|---|---|---|
displayDecimals |
Display decimal places for all currencies (0-8, default 2). Truncates (floors) — does not round, so displayed amounts never exceed actual value. Does not affect internal storage. | 2 |
displayDateFormat |
PHP date format string | Y-m-d H:i:s.u |
Interactive Mode:
Running eiou changesettings without arguments enters interactive mode, which displays all current settings then presents a numbered menu of all changeable settings grouped by category. All settings available via direct command-line mode are also available interactively.
Examples:
# Interactive mode (shows all settings, prompts for selection)
eiou changesettings
# Direct setting change
eiou changesettings defaultCurrency VWL
eiou changesettings maxP2pLevel 5
eiou changesettings maxOutput 0 # Unlimited output
eiou changesettings autoBackupEnabled false
eiou changesettings autoAcceptTransaction false # Require approval before sending P2P
eiou changesettings trustedProxies "10.0.0.1,172.16.0.1"
eiou changesettings trustedProxies "" # Clear (trust no proxies)
eiou changesettings name "My Node"
eiou changesettings allowedCurrencies "VWL,EUR"
# Advanced settings
eiou changesettings logLevel WARNING
eiou changesettings backupRetentionCount 5
eiou changesettings cleanupDeliveryRetentionDays 60
eiou changesettings paymentRequestsArchiveRetentionDays 90
eiou changesettings paymentRequestsArchiveBatchSize 1000
eiou changesettings transactionsArchiveRetentionDays 90
eiou changesettings transactionsArchiveBatchSize 1000
eiou changesettings httpTransportTimeoutSeconds 30
eiou changesettings rateLimitEnabled false
eiou changesettings displayDecimals 4
eiou changesettings torCircuitMaxFailures 5
eiou changesettings torFailureTransportFallback false
eiou changesettings contactStatusEnabled false
# JSON output
eiou changesettings defaultFee 1.5 --json
Reset all settings to defaults:
eiou changesettings reset wipes every saved setting in /etc/eiou/config/defaultconfig.json back to the values this build of the code considers default (each getter in UserContext falls back to its Constants::-backed default when the override is absent). The display name in userconfig.json is also cleared; identity fields (keys, hostnames, onion address) are preserved. Destructive, so the bare form prints an error and requires --yes / -y to confirm.
“Defaults” here means whatever the running code treats as default — if an operator has edited Constants.php on this node, this resets to the operator’s edited values, not the upstream ship defaults. Contacts, transactions, backups, and API keys are never touched.
# Safety check — prints an error, does nothing:
eiou changesettings reset
# Actually reset:
eiou changesettings reset --yes
The same operation is exposed in the GUI under Settings → Advanced Settings → Reset to Defaults (typed-confirmation modal).
System Commands
sync
Synchronize data with contacts.
After syncing transactions, chain integrity is verified locally for each contact. If gaps remain (e.g., both sides are missing the same transactions), the output reports the gap count and recommends using chaindrop to resolve.
Syntax:
eiou sync [type]
Arguments:
| Argument | Type | Description |
|---|---|---|
type |
optional | Sync type: contacts, transactions, balances |
Examples:
# Sync everything
eiou sync
# Sync only contacts
eiou sync contacts
# Sync only transactions (includes backup recovery)
eiou sync transactions
# Recalculate balances from transaction history
eiou sync balances
Notes:
- Transaction sync verifies chain integrity locally for each contact
- If gaps are found, backup recovery is attempted on both sides (local backups first, then remote)
- If gaps remain after recovery, the output reports the gap count and recommends using
chaindropto resolve
help
Display help information for top-level commands.
Syntax:
eiou help [command]
Arguments:
| Argument | Type | Description |
|---|---|---|
command |
optional | Specific top-level command to get detailed help for |
Examples:
# General help
eiou help
# Help for specific top-level command
eiou help send
eiou help apikey
# JSON format
eiou help --json
Namespaced subcommand help. Every namespace that owns a CLI subtree — apikey, contact, chaindrop, payback — delegates eiou help <namespace> straight into that namespace’s own help. eiou help <ns> and eiou <ns> (or eiou <ns> help) print the exact same subcommand tree, so help lives in exactly one place per namespace and never drifts.
eiou contact # full contact subcommand tree
eiou help contact # ← identical output, delegated to the contact handler
eiou contact currency # per-currency subcommand tree
eiou help contact currency # ← identical output, delegated to the same handler
eiou apikey # full API key help
eiou help apikey # ← identical output
eiou chaindrop # full chain drop help
eiou help chaindrop # ← identical output
eiou payback # full payback methods help
eiou help payback # ← identical output
There is no eiou help <namespace> <subcommand> drill-down form — read the subcommand line you want from the namespace’s full tree and use it directly. Top-level (non-namespaced) commands like info, send, viewsettings still render their detailed help via eiou help <command> as documented above.
updatecheck
Check Docker Hub and GitHub Releases for newer image versions. Bypasses the 24-hour cache and performs a fresh check.
Syntax:
eiou updatecheck
Examples:
# Check for updates
eiou updatecheck
# JSON output
eiou updatecheck --json
Output:
- If an update is available: shows the latest version and a
docker pullcommand - If up to date: confirms the current version
- If check fails: reports that Docker Hub and GitHub could not be reached
shutdown
Gracefully shutdown the wallet application. Stops all message processors and sets a shutdown flag to prevent the watchdog from restarting them.
Syntax:
eiou shutdown
Behavior:
- Sends SIGTERM to all running processors (P2P, Transaction, Cleanup, ContactStatus)
- Removes PID and lockfiles
- Creates
/tmp/eiou_shutdown.flagto prevent watchdog restarts - Releases application resources (database connections, services)
Use eiou start to resume processor operations after a shutdown.
start
Resume processor operations after a previous eiou shutdown.
Syntax:
eiou start
Behavior:
- Removes the shutdown flag (
/tmp/eiou_shutdown.flag) - The watchdog detects the flag removal and restarts all processors within 30 seconds
- Restart counters are reset so processors are not blocked by pre-shutdown limits
- If no shutdown flag exists (processors are already running), the command reports that and exits
restart
Full in-place node restart: respawn processors and PHP-FPM workers so freshly-enabled plugins (or any other startup-bound state) take effect without a container reboot.
Syntax:
eiou restart
Behavior:
- Sends SIGTERM to all running processors (the watchdog respawns them within ~30s)
- Sends SIGUSR2 to the PHP-FPM master so all workers gracefully recycle (in-flight HTTP requests finish before the worker exits)
- Required when toggling plugins, since event subscriptions bind during boot
- Must run as root inside the container — the CLI process does, calling from a PHP-FPM worker (GUI) does not. The REST equivalent (
POST /api/v1/system/restart) sidesteps this by writing a request marker that the root-side poller instartup.shpicks up.
retire
Retire (decommission) this node: stop its message processors and persist a flag so the node skips processors and Tor hidden-service publication on every boot until eiou unretire.
Syntax:
eiou retire
Behavior:
- Marks the node retired and stops the message processors (the watchdog will not respawn them while retired)
- Tears down the Tor hidden service so the node stops publishing its
.onion, and stays down across reboots - Used when moving a wallet identity to another node: the seed deterministically derives the same
.onion, so two live nodes fight over one hidden service and split history across two databases - A node reached only over Tor must be reactivated via HTTP/HTTPS or the CLI, since retiring removes the
.onion
The REST equivalent is POST /api/v1/system/retire (requires {"confirm": true}, system:write).
unretire
Reverse eiou retire: reactivate this node and republish its Tor hidden service.
Syntax:
eiou unretire
Behavior:
- Clears the retired flag; the processors resume within ~30s and the hidden service republishes within a few seconds
- Only safe when no other node is currently running this wallet identity, or the two will fight over the hidden service and corrupt transaction history
The REST equivalent is POST /api/v1/system/unretire (requires {"confirm": true}, system:write).
API Key Management
apikey
Manage API keys for external REST API access.
Syntax:
eiou apikey <action> [args...]
Actions:
| Action | Syntax | Description |
|---|---|---|
create |
apikey create <name> [permissions] |
Create new API key |
list |
apikey list |
List all API keys |
delete |
apikey delete <key_id> |
Permanently delete a key |
disable |
apikey disable <key_id> |
Temporarily disable a key |
enable |
apikey enable <key_id> |
Re-enable a disabled key |
help |
apikey help |
Show detailed API key help |
Available Permissions:
| Permission | Description |
|---|---|
wallet:read |
Read wallet balance and transactions |
wallet:send |
Send transactions |
contacts:read |
List and view contacts |
contacts:write |
Add, update, delete contacts |
system:read |
View system status and metrics |
admin |
Full administrative access |
all |
All permissions (same as admin) |
Examples:
# Create API key with default permissions
eiou apikey create "My Mobile App"
# Create with specific permissions
eiou apikey create "Read Only" wallet:read,contacts:read
# List all keys
eiou apikey list
# Delete a key
eiou apikey delete eiou_abc123
# Disable/Enable
eiou apikey disable eiou_abc123
eiou apikey enable eiou_abc123
Important: The API secret is only shown once at creation time. Store it securely.
Alternate Auth Code
altcode
Manage the alternate authentication code — a user-chosen passphrase that can be submitted at the GUI login form or the sensitive-action gate alongside the seed-derived primary auth code. Useful because the primary is 20 random hex characters that aren’t memorable; the alt code is whatever the operator can actually recall.
Syntax:
eiou altcode <action>
Actions:
| Action | Syntax | Description |
|---|---|---|
status |
altcode status |
Show whether an alt code is currently set |
set |
altcode set |
Set or rotate the alt code (interactively prompts for the primary first; then for the new alt code with confirmation) |
clear |
altcode clear |
Remove the alt code (interactively prompts for the primary first) |
help |
altcode help |
Show detailed alt-code help |
Strength rules (enforced server-side and mirrored in the GUI):
- minimum 12 characters
- at least one uppercase letter, one lowercase letter, one digit, one symbol
- no three repeated characters in a row (
aaa,111) - no monotonic ascending/descending run of length 4+ (
abcd,4321) - not a substring of a bundled common-password list
Examples:
# Check status (no secrets read)
eiou altcode status
# Set (prompts: Primary auth code → New alt code → Confirm new alt code)
eiou altcode set
# Remove (prompts: Primary auth code)
eiou altcode clear
Security notes:
- Set / clear always require the primary auth code. The alt code itself can never rotate or remove itself — this prevents an attacker who learns the alt code from locking the legitimate operator out.
- Inputs are read with
stty -echowhen stdin is a TTY so the plaintext does not appear in shell history or terminal scrollback. - Stored as a one-way Argon2id hash in
userconfig.jsonunderaltcode_hash. Forgetting it is recoverable only by re-runningaltcode setfrom a session that authenticates with the primary; there is no separate recovery code. - The CLI rate limiter caps
altcodeinvocations at 5 attempts per 5 minutes to slow online brute-force against the primary.
Payback Methods
payback
Manage your own payback methods — the settlement rails (bank wire, PayPal, Bitcoin, custom free-text, etc.) you offer contacts so they can settle debts they owe you. Each method is encrypted at rest per-row; sensitive fields only leave the node when you explicitly reveal them (via show) or a contact fetches them over E2E.
Syntax:
eiou payback <action> [args...]
Actions:
| Action | Syntax | Description |
|---|---|---|
list |
payback list [--currency <c>] [--all] |
List all enabled methods. --currency filters to one code; --all also includes disabled rows. |
add |
payback add <type> <label> <currency> [--share auto|never] [--priority N] |
Create a new method. Type-specific fields are prompted interactively (sensitive inputs use stty -echo when stdin is a TTY). |
show |
payback show <method_id> |
Display a single method with all fields decrypted to plaintext. |
edit |
payback edit <method_id> |
Re-enter the type-specific fields. Label, priority, and share policy have their own subcommands. |
remove |
payback remove <method_id> |
Permanently delete a method. |
share-policy |
payback share-policy <method_id> auto|never |
Update only the share policy on an existing method. |
help |
payback help |
Show detailed help. |
Supported Types (core):
23 rail types ship in core. The currency code (<currency> in the
add command) is the asset code itself — for token rails like USDC,
USDT, EURC the eIOU ledger treats each token as its own currency, not
as the pegged fiat. See /docs/reference/plugins “Currency binding” for the rationale.
| Group | Types |
|---|---|
| Bank | bank_wire (sub-rails: sepa, faster_payments, ach, fednow, swift — validates IBAN mod-97 and ABA-routing checksum) |
| Crypto | btc, evm (Ethereum mainnet plus Polygon / BSC / Avalanche / Arbitrum / Optimism / Base / Linea / zkSync Era / Scroll / Gnosis Chain, native asset plus ERC-20 tokens with canonical contract lookup), solana (SOL plus SPL tokens), tron (TRX plus TRC-20 tokens), lightning (BOLT11 / LNURL / Lightning Address), xrp (with optional destination tag), stellar (XLM plus Stellar-issued assets with SEP-7 URI), monero (standard or integrated address with optional legacy payment_id), utxo_alt (LTC / BCH / DOGE), ton (TON / Telegram Wallet ecosystem; Jettons USDT-TON, NOT), cardano (ADA, Shelley bech32, CIP-13 URI), algorand (ALGO plus ASAs USDC, USDT; ARC-26 URI) |
| P2P | venmo, paypal (PayPal.me handle or email), revolut (revtag), wise (wisetag / email / IBAN), cashapp, zelle (email / phone), pix (5 key types), upi (Indian VPA), mobile_payment (Swish / Vipps / MobilePay / TWINT / Bizum / BLIK), alipay, wechat_pay, interac (Canada e-Transfer; email / phone), exchange_p2p (Coinbase / Binance Pay / Crypto.com / OKX / Bybit / KuCoin; email / phone / pay_id / uid / username depending on service), mercadopago (Argentina / Brazil / Mexico; alias / cvu / cbu / cpf / clabe / email / phone depending on country), paynow (Singapore; mobile / NRIC / UEN; emits an SGQR EMV-QR payload) |
| Other | custom (free-text key/value rows up to 50 rows × 64-char key × 1024-char value, declared currency) |
Plugins can add further rails (e.g. niche regional networks, new
chains, custom gift-card systems) by registering a
PaybackMethodTypeContract — see docs//docs/reference/plugins for authoring.
Core-reserved ids (any of the 22 above) cannot be shadowed.
Share Policies:
| Policy | Behaviour when a contact’s node fetches your methods |
|---|---|
auto |
Any accepted contact can fetch without owner approval (default) |
never |
Method is never shared via the E2E fetch flow |
Priority: Integer 0–9999, lower = preferred. Used as a tiebreaker when several methods of yours match the same currency (defaults to 100).
Examples:
# List all enabled methods
eiou payback list
# List only USD methods, including disabled ones
eiou payback list --currency USD --all
# JSON output for scripting
eiou payback list --json
# Add a SEPA bank-wire method (prompts for rail, name, IBAN)
eiou payback add bank_wire "My Revolut" EUR
# Add a custom free-text method, never auto-shared with contacts, top priority
eiou payback add custom "Monzo – DM me" GBP --share never --priority 10
# Add a Bitcoin method (prompts for address; memo optional)
eiou payback add btc "My BTC" BTC
# Add a USDC-on-Polygon method (prompts: EVM address, chain, optional
# token contract override, optional memo). USDC is its own currency code
# in eIOU — settling 100 USDC means 100 USDC on the picked chain.
eiou payback add evm "My USDC on Polygon" USDC
# Add a Lightning Address method (prompts: kind = lightning_address, identifier)
eiou payback add lightning "My LN" BTC
# Add a Brazilian Pix method (prompts: key kind = email/phone/cpf/cnpj/random, key)
eiou payback add pix "Pix CPF" BRL
# Add a Swedish Swish method (prompts: service = swish, identifier as E.164 phone)
eiou payback add mobile_payment "Swish" SEK
# Add a TON method (prompts for the 48-char EQ.../UQ... address; canonical
# USDT-TON and NOT jetton masters are looked up automatically — set the
# optional jetton_master override only for non-canonical variants)
eiou payback add ton "My TON" TON
# Add a Cardano method (prompts for the Shelley bech32 addr1... address;
# ADA-only — CIP-13 doesn't carry native-token info in the URI)
eiou payback add cardano "My ADA" ADA
# Add an Algorand method (prompts for 58-char base32 address; canonical
# USDC and USDT ASA ids are looked up automatically — set the optional
# asset_id override only for non-canonical ASAs)
eiou payback add algorand "My USDC on Algorand" USDC
# Add an Interac e-Transfer method (CAD only; prompts: identifier kind,
# email or phone, optional autodeposit flag)
eiou payback add interac "Interac (email)" CAD
# Add a Coinbase exchange-to-exchange method (off-chain Coinbase-to-Coinbase
# send by email; instant, free; only works when payer is also on Coinbase)
eiou payback add exchange_p2p "Coinbase USDC" USDC
# Add a Binance Pay method (16-digit Pay ID, or email, or phone)
eiou payback add exchange_p2p "Binance Pay ID" USDT
# Add a MercadoPago method (Argentine alias — the friendly handle that
# points to the operator's CVU/CBU under the hood)
eiou payback add mercadopago "MercadoPago AR" ARS
# Add a PayNow method (Singapore; SGD only). The Pay button emits an
# SGQR EMV-QR payload that every SG bank app scans or accepts pasted.
eiou payback add paynow "PayNow (mobile)" SGD
# Reveal a method's plaintext fields (does not re-prompt for auth — CLI is trusted)
eiou payback show pbm_abc123
# Update the share policy on an existing method
eiou payback share-policy pbm_abc123 never
# Remove a method
eiou payback remove pbm_abc123
Notes:
showprints fully-decrypted plaintext. The GUI and REST API gate plaintext reveal behind a sensitive-action authcode prompt, but the CLI is considered already-authenticated by virtue of having shell/container access.editonly re-enters the type-specific fields (re-encrypts the whole blob atomically). To change just the label or priority, use the REST API or GUI.- Method IDs are UUIDs returned in the
addresponse and visible inlistoutput.
Payment Request Commands
request
Manage payment requests — ask a contact to pay you a specific amount. The recipient can approve (which sends the eIOU automatically), decline, or you can cancel your own outgoing requests.
Syntax:
eiou request [subcommand] [args...]
Subcommands:
| Subcommand | Syntax | Description |
|---|---|---|
| (none/list) | eiou request |
List all incoming and outgoing payment requests |
create |
eiou request create <contact> <amount> <currency> [description] |
Create and send a payment request to a contact |
approve |
eiou request approve <request_id> [note] |
Approve an incoming request (sends eIOU automatically). The request moves to sending and resolves to approved once the payment completes or failed if it terminally fails. Optional [note] is appended to the on-chain description with " | " (e.g. "paid via coinbase txid abc"). |
retry |
eiou request retry <request_id> |
Re-send the payment for an incoming request whose previous attempt failed |
decline |
eiou request decline <request_id> |
Decline an incoming payment request |
cancel |
eiou request cancel <request_id> |
Cancel an outgoing request you created |
Examples:
# List all payment requests
eiou request list
eiou request list --json
# Request 25 VWL from Alice
eiou request create "Alice" 25.00 VWL "Dinner last week"
# Request payment using a contact address (avoids duplicate name ambiguity)
eiou request create "http://alice-node.example.com" 50.00 VWL
# Approve an incoming request (pays the requester)
eiou request approve req_abc123def456
# Approve and append a payer note to the on-chain description.
# Final description becomes "payment: <requester desc> | <your note>" —
# the note is capped against whatever space is left under the 255-char
# ceiling and rejected with a clear error if it doesn't fit.
eiou request approve req_abc123def456 "paid via coinbase txid abc"
# Decline a request
eiou request decline req_abc123def456
# Cancel your own outgoing request (only while pending)
eiou request cancel req_abc123def456
Notes:
- When you approve a request,
sendEiouis called internally — the full transaction pipeline applies (P2P routing, credit checks, DLQ retries) - If multiple contacts share the same name,
createreturns an error listing the matching contacts and their addresses — use an address instead - Cancelling sends a cancellation message to the recipient; if they already approved before the cancel arrives, the payment takes priority
- Request IDs are returned in the
createresponse and visible inlistoutput
Tx Drop Commands
chaindrop
Manage tx drop agreements for resolving transaction chain gaps.
When both contacts are missing one or more of the same transactions in their shared chain, the chain cannot be repaired via sync. Tx drop resolves this by mutually agreeing to remove the missing transaction(s) and re-wire the chain around the drop (a single tx drop operation can span one or more consecutive missing transactions; non-consecutive gaps require a separate proposal per run of consecutive missing txs).
Important: While a chain gap exists, transactions with that contact are blocked. Chain gaps are detected locally by send, sync, and ping — all three commands verify chain integrity without exchanging transaction lists over the wire. Before resorting to a tx drop, the sync flow attempts backup recovery: the local node checks its own backups first (self-repair), then tells the remote node which txids are still missing so it can check its backups too. If either side has the missing transactions in a backup, the chain is repaired without a tx drop. Only when neither side has a backup does the send command auto-propose a tx drop. Rejecting a proposal leaves the gap unresolved, meaning the contacts cannot transact until a new proposal is accepted or the missing transactions are recovered.
Syntax:
eiou chaindrop <action> [args...]
Actions:
| Action | Syntax | Description |
|---|---|---|
propose |
chaindrop propose <contact_address> |
Propose dropping a missing transaction |
accept |
chaindrop accept <proposal_id> |
Accept an incoming proposal |
reject |
chaindrop reject <proposal_id> |
Reject an incoming proposal |
list |
chaindrop list [contact_address] |
List pending proposals |
help |
chaindrop help |
Show tx drop help |
Arguments:
| Argument | Type | Description |
|---|---|---|
contact_address |
required (propose) | Contact’s node address (HTTP, HTTPS, or Tor) |
proposal_id |
required (accept/reject) | The proposal ID to act on (format: cdp-...) |
contact_address |
optional (list) | Filter proposals by contact address |
Examples:
# Propose dropping a missing transaction (auto-detects the gap)
eiou chaindrop propose https://bob
# List all incoming pending proposals
eiou chaindrop list
# List proposals for a specific contact
eiou chaindrop list https://bob
# Accept a proposal (executes drop, re-signs transactions, exchanges data)
eiou chaindrop accept cdp-2c3c26ba61ab4073
# Reject a proposal (WARNING: gap remains unresolved, transactions stay blocked)
eiou chaindrop reject cdp-2c3c26ba61ab4073
# JSON output
eiou chaindrop propose https://bob --json
eiou chaindrop list --json
eiou chaindrop accept cdp-2c3c26ba61ab4073 --json
Gap Detection and Recovery:
Chain gaps are detected locally by three commands:
send— verifies chain integrity before every transaction; triggers sync to repair (which includes backup recovery on both sides); auto-proposes a tx drop only if sync fails to repair the gapsync— verifies chain integrity, attempts local backup recovery before contacting the remote node, and asks the remote to check its backups for any remaining gapsping— verifies local chain integrity (not just chain head comparison); triggers sync if chains don’t match; auto-proposes a tx drop if sync detects mutual gaps (both sides missing the same transaction(s))
All detection is local — no transaction lists are sent over the wire.
Recovery priority:
- Local backup recovery — during sync, the node checks its own database backups for missing transactions
- Remote backup recovery — remaining missing txids are sent to the contact, who checks its DB and backups
- Tx drop — only if neither side has the missing transactions in any backup; drops the missing run(s) and re-wires the chain around them
Flow (when backup recovery fails):
- Contact A detects chain gap (
sendorpingauto-proposes, orsyncreveals the gap) - Sync attempts backup recovery on both sides (automatic, no user action needed)
- If recovery fails and auto-propose is enabled (
EIOU_AUTO_CHAIN_DROP_PROPOSE=true, default), a tx drop is auto-proposed bysendorping; alternatively, Contact A runs:eiou chaindrop propose <contact_B_address> - If auto-accept is enabled (
EIOU_AUTO_CHAIN_DROP_ACCEPT=true, default OFF), Contact B’s node auto-accepts the proposal. If the balance guard is enabled (EIOU_AUTO_CHAIN_DROP_ACCEPT_GUARD=true, default), it first checks that missing transactions don’t include net payments owed to us. If the guard blocks or auto-accept is disabled, the proposal requires manual review. - Contact B checks incoming proposals:
eiou chaindrop list(or sees GUI notification banner) - Contact B runs:
eiou chaindrop accept <proposal_id>(or accepts via GUI) - Both chains are repaired, balances recalculated, and transactions can resume
For multiple gaps, repeat the propose/accept cycle for each gap.
JSON Response Examples:
Propose (success):
{
"success": true,
"data": {
"message": "Chain drop proposal sent",
"proposal_id": "cdp-2c3c26ba61ab4073...",
"missing_txid": "a1b2c3d4..."
}
}
List proposals:
{
"success": true,
"data": {
"message": "Chain drop proposals",
"count": 1,
"proposals": [
{
"proposal_id": "cdp-2c3c26ba61ab4073...",
"contact_pubkey_hash": "abc123...",
"missing_txid": "a1b2c3d4...",
"broken_txid": "e5f6g7h8...",
"status": "pending",
"direction": "incoming",
"created_at": "2026-02-07 12:00:00"
}
]
}
}
Accept (success):
{
"success": true,
"data": {
"message": "Chain drop proposal accepted and executed",
"proposal_id": "cdp-2c3c26ba61ab4073..."
}
}
Reject (success):
{
"success": true,
"data": {
"message": "Chain drop proposal rejected",
"proposal_id": "cdp-2c3c26ba61ab4073..."
},
"warning": "The chain gap remains unresolved. Transactions with this contact are blocked until a new chain drop proposal is accepted."
}
On Failure (JSON):
{
"success": false,
"error": {
"code": "CONTACT_NOT_FOUND",
"message": "Contact not found: https://unknown"
}
}
Notes:
proposeauto-detects the chain gap by verifying chain integrity with the specified contactacceptexecutes the tx drop locally, re-signs affected transactions, and exchanges re-signed copies with the proposerrejectleaves the chain gap unresolved — transactions remain blocked until a new proposal is accepted- Proposals expire automatically after their configured timeout
- Rate limited: 10 tx drop operations per minute
- Auto-propose controlled by
EIOU_AUTO_CHAIN_DROP_PROPOSEenv var (default:true) - Auto-accept controlled by
EIOU_AUTO_CHAIN_DROP_ACCEPTenv var (default:false— requires manual accept) - Balance guard controlled by
EIOU_AUTO_CHAIN_DROP_ACCEPT_GUARDenv var (default:true). When enabled, blocks auto-accept if missing transactions include net payments owed to us. Set tofalsefor unconditional auto-accept.
Backup Commands
backup
Manage encrypted database backups.
Syntax:
eiou backup <action> [args...]
Actions:
| Action | Syntax | Description |
|---|---|---|
create |
backup create |
Create a new encrypted backup |
restore |
backup restore <filename> --confirm |
Internal boot-recovery command; not callable from a serving container |
list |
backup list |
List all available backups |
verify |
backup verify <filename> |
Verify backup integrity |
delete |
backup delete <filename> |
Delete a specific backup |
enable |
backup enable |
Enable automatic daily backups |
disable |
backup disable |
Disable automatic daily backups |
status |
backup status |
Show backup system status |
cleanup |
backup cleanup |
Remove old backups (keep 3 most recent per type) |
help |
backup help |
Show backup help |
Examples:
# Create a new backup
eiou backup create
# List all backups
eiou backup list
# Verify a specific backup
eiou backup verify backup_20260125_120000.eiou.enc
# Restore by starting a new-volume candidate in boot recovery mode
EIOU_BOOT_RECOVERY_BACKUP=backup_20260125_120000.eiou.enc docker compose up
# Check backup status
eiou backup status
# Enable/disable automatic backups
eiou backup enable
eiou backup disable
# JSON output
eiou backup list --json
eiou backup status --json
Security Notes:
- Backups are encrypted with AES-256-GCM using the master key (derived from your seed phrase)
- Restore requires wallet restoration first (the master key is re-derived from the seed phrase)
- Backup directory has restricted permissions (700)
- Rate limited: 10 backup operations per minute
Backup Storage:
- Location:
/var/lib/eiou/backups/ - Filename format:
backup_YYYYMMDD_HHmmss.eiou.enc— coherent full-database snapshot containing live, archive, and chain-checkpoint tablesarchive_backup_YYYYMMDD_HHmmss.eiou.enc— the same coherent full snapshot, triggered after archival moves rows
- Retention: 3 most recent backups per prefix (configurable via
backupRetentionCount); scheduled snapshots never evict archive-triggered recovery points - Both prefixes use chunked authenticated full-snapshot format v3. Restore is a root-controlled pre-service boot operation into a new, empty database; it cannot run through GUI/API workers or an ordinary
docker exec. - Format cutoff: pre-v0.1.18-alpha artifacts are rejected. Restore them with the earlier image, then create a v3 snapshot.
Payment Request Archival:
The archival cron moves resolved payment requests older than paymentRequestsArchiveRetentionDays into payment_requests_archive. Run it manually for a preflight check or off-schedule sweep:
# Dry-run: count eligible rows, make no changes
php /app/eiou/scripts/payment-request-archive-cron.php --dry-run
# Normal run: move up to paymentRequestsArchiveBatchSize rows and trigger an archive_backup_* dump
php /app/eiou/scripts/payment-request-archive-cron.php
Logs are written to /var/log/eiou/payment-request-archive.log. A backup failure during archival is logged as WARNING but never fails the archival run itself — rows are already safely moved, and the next archival run that moves rows will re-attempt the archive backup.
Transactions Archival:
The archival cron moves completed transactions older than transactionsArchiveRetentionDays into transactions_archive, gated per bilateral pair on a gap-free chain-integrity check. Pairs with a detected gap are skipped (not archived) so the gap stays inspectable; clean pairs get a row upserted in transaction_chain_checkpoints recording the gap-free-at-archival proof. Runs nightly at 01:30 UTC (offset 30m from the payment-request archival at 01:00).
# Dry-run: count eligible pairs + rows, make no changes
php /app/eiou/scripts/transaction-archive-cron.php --dry-run
# Normal run: verify per pair, move up to transactionsArchiveBatchSize rows per pair
php /app/eiou/scripts/transaction-archive-cron.php
Logs are written to /var/log/eiou/transaction-archive.log. The run’s JSON output includes pairs_processed, pairs_archived, pairs_skipped_gap, moved, batches, and archive_backup_file — pairs_skipped_gap > 0 is worth investigating (a gap is either a local data issue or a missing sync). The per-pair checkpoint written here is consumed by verifyChainIntegrity() on every outbound send, so the send hot-path stays O(recent tail) regardless of total history size.
Export Commands
export
Stream a portion of the wallet database to stdout (default) or to a file as CSV or NDJSON. Designed for accounting, audit, and external-tool consumption. Distinct from backup: backup produces a full encrypted snapshot for disaster recovery; export is selective, plaintext, human-friendly, and not intended for round-trip restore.
Syntax:
eiou export <entity> [flags...]
Entities:
| Entity | Description |
|---|---|
transactions |
Wallet transactions (live + archive), oldest first |
payment_requests |
Incoming + outgoing payment requests (live + archive), oldest first |
contacts |
Address book snapshot — one row per contact, name ASC |
balances |
One row per (contact, currency), grouped by currency |
Common flags:
| Flag | Values | Description |
|---|---|---|
--format |
csv, json |
Output format (default csv). CSV ships with UTF-8 BOM, CRLF terminators, RFC 4180 quoting. JSON is NDJSON (one object per line). |
--view |
slim, full |
Field set (default slim). slim is accountant-friendly (txid, date, direction, status, counterparty, currency, amount, description); full adds audit fields (addresses, signatures, signed message body, chain links, source table, routing marker). |
-o FILE / --output=FILE |
path | Write to FILE instead of stdout. |
Entity-specific filters:
--contact=NAME is supported on both entities and restricts to the bilateral subset involving that contact.
Transactions only:
| Flag | Example | Description |
|---|---|---|
--status |
--status=completed |
pending, sending, sent, accepted, rejected, cancelled, completed, failed. |
--type |
--type=sent |
Direction: sent, received, relay. |
Payment requests only:
| Flag | Example | Description |
|---|---|---|
--status |
--status=approved |
pending, approved, declined, cancelled, expired. |
--direction |
--direction=outgoing |
incoming (someone is asking you to pay) or outgoing (you are asking someone to pay). |
Contacts only:
| Flag | Example | Description |
|---|---|---|
--status |
--status=accepted |
accepted, pending, blocked. |
Contacts does not accept --contact — filtering to a single contact is always a one-row export which isn’t useful.
Balances only:
| Flag | Example | Description |
|---|---|---|
--currency |
--currency=VWL |
Restrict to a single currency code. |
--contact |
--contact=alice |
Restrict to a single contact (combine with --currency for one balance row). |
Date filters (transactions + payment_requests only):
| Flag | Example | Description |
|---|---|---|
--from |
--from=2026-01-01 |
Inclusive lower bound on date (UTC). |
--to |
--to=2026-12-31 |
Inclusive upper bound on date (UTC). |
Examples:
# Dump all transactions to a CSV file
eiou export transactions > my-history.csv
# Audit-grade JSON of every interaction with Alice
eiou export transactions --format=json --view=full --contact=alice -o alice.ndjson
# This year's pending transactions only
eiou export transactions --status=pending --from=2026-01-01
# Approved outgoing payment requests
eiou export payment_requests --direction=outgoing --status=approved
# Address book snapshot for migration
eiou export contacts --status=accepted --view=full -o address-book.csv
# Per-currency balances grouped by currency
eiou export balances --view=full -o balances.csv
# Just the VWL balance with Alice
eiou export balances --currency=VWL --contact=alice
# Help
eiou export help
Payment request field set: Slim view has request_id, date, direction, status, counterparty (name + pubkey hash), currency, amount triplet, description. Full view adds requester/recipient pubkey hashes, requester address, expires_at, responded_at, resulting_txid, signed message body, the request’s stored contact_name snapshot (preserved from creation time so it survives the contact being deleted from the address book), and source_table.
Amount columns: All three are emitted side-by-side — amount_decimal (string, 8 fractional digits), amount_whole (int), amount_frac (int). Spreadsheet consumers can use the decimal; precision-sensitive tools can reconstruct from whole + frac.
Date format: ISO 8601 UTC, YYYY-MM-DDTHH:MM:SSZ.
Counterparty name resolution: Names come from the accepted-contacts table cached once at export start (single lookup, not per-row). Counterparties not in the address book (unknown peers, blocked contacts) have empty counterparty_name but always have counterparty_pubkey_hash.
Mid-stream error contract: Once streaming has begun (headers sent, body started), a mid-stream failure cannot retroactively send a 5xx. Instead, the export emits a format-appropriate sentinel and exits non-zero:
- CSV: final row begins with
#ERROR <message>(visibly not a data row). - NDJSON: final line is
{"_error": "...", "_partial": true}.
Shell pipelines that check exit code will fail loudly.
Exit codes:
0— export completed (header + zero or more rows written cleanly).1— argument / lookup / I/O failure before streaming, OR mid-stream failure (sentinel was emitted).
Chain Integrity Audit
verify-chain
Walk every bilateral chain on this node end-to-end, bypassing the hot-path checkpoint-trust optimization, and recompute each pair’s archive hash to detect tampering. Use when auditing a node after a restore, investigating a pairs_skipped_gap from the archival cron, or generally checking that the on-disk archive is consistent with what the checkpoint says it should be.
Usage:
eiou verify-chain
Output (per pair, to stdout):
transactions: N settled (across live + archive)chain: OKorchain: FAIL - N gap(s)with the missing txidscheckpoint: none(pair has no archive yet),checkpoint: archive hash matches stored value, orcheckpoint: FAIL - archive hash mismatch(archive was modified outside the archival service)
Exit codes:
0— every pair clean1— at least one pair has a finding (chain gap or hash mismatch)
This command is intentionally NOT on any cron — it’s O(all history) per pair, which is the cost the per-pair checkpoint avoids on the hot path. Run it deliberately.
Plugin Management
plugin
List installed plugins and toggle their enabled flag. Persistence-only — does not restart the node; you must follow up with eiou restart (or POST /api/v1/system/restart, or the GUI restart button) for an enable/disable to take effect, since event subscriptions bind during boot.
Syntax:
eiou plugin [list|enable|disable|uninstall] [name]
Subcommands:
| Subcommand | Syntax | Description |
|---|---|---|
(none / list) |
eiou plugin |
List every installed plugin with version, enabled flag, status, license. |
enable |
eiou plugin enable <name> |
Persist the enabled flag as true. If the plugin declares public routes but they won’t be served (node ceiling off, or allow with this plugin’s per-plugin toggle off), it also prints a hosting-aware Note: explaining the routes are gated and how to turn them on. |
disable |
eiou plugin disable <name> |
Persist the enabled flag as false. |
public-routes |
eiou plugin public-routes <name> on|off |
Turn the plugin’s public HTTP routes (/p/<id>/) on or off. Live when the node’s EIOU_PUBLIC_PLUGIN_ROUTES ceiling is allow, which is the default; the preference is persisted regardless, but one recorded under an off ceiling does not go live when that ceiling is raised — run the command again on a node that permits public routes. Re-renders nginx immediately. |
uninstall |
eiou plugin uninstall <name> |
Run the full uninstall sequence (onUninstall hook, drop tables, drop user, delete credentials, remove files). The plugin must be disabled first. |
Examples:
# List all plugins (table)
eiou plugin
# List as JSON (full metadata)
eiou plugin list --json
# Enable / disable
eiou plugin enable hello-eiou
eiou plugin disable hello-eiou
# Uninstall a disabled plugin
eiou plugin uninstall hello-eiou
# Apply the change
eiou restart
Notes:
- Persists to
/etc/eiou/config/plugins.jsonimmediately. - Plugin names are validated against
^[a-z0-9][a-z0-9-_]{0,63}$(kebab-case alphanumerics). - Plugins disabled by default at install time — see /docs/reference/plugins for the safety stance.
- Plugin-owned CLI verbs are dispatched via
PluginCliRegistry; if a plugin registers a top-level verb, it falls through after core’selsebranch inEiou.php. See /docs/reference/plugins for plugin authoring.
Report Commands
report
Generate reports for troubleshooting and analysis.
Usage:
eiou report <type> [description] [--full] [--send]
Available report types:
| Type | Description |
|---|---|
debug |
System info, debug table entries, application logs, PHP errors, nginx errors |
Options:
| Option | Description |
|---|---|
--full |
Include full log history (default: last 50 lines per log file) |
--send |
Submit report to support via Tor instead of saving to file |
Examples:
# Generate a limited debug report
eiou report debug
# Include an issue description
eiou report debug "login page crash"
# Full report with complete log history
eiou report debug --full
# Full report with description
eiou report debug "sync failure after restore" --full
# Send report to support instead of saving to file
eiou report debug --send
# Send full report with description to support
eiou report debug "login crash" --full --send
Output (default): Reports are saved as JSON files in /tmp/ (e.g., /tmp/eiou-debug-report-20260314170000.json). The file path and size are printed to stdout. With --json, structured output includes path, size, report_type, and debug_entries count.
Output (--send): The report is scrubbed of sensitive data (addresses, keys, IPs) and submitted to the support endpoint via Tor. On success, a reference key is returned. Rate-limited to 3 submissions per day. With --json, structured output includes key and report_type.
Report Contents:
- System info: PHP version, MariaDB version, OS, memory limits, loaded extensions
- Application constants and user configuration (
defaultconfig.json) - PHP config (
php.ini) and nginx config - Debug table entries (from
DebugService::output()calls) - PHP error log, nginx error log, eIOU application log
Notes:
- Same report format as the GUI Debug Report (both use
DebugReportService) - Limited mode includes last 50 lines of each log file; full mode includes up to 5MB per log
- Reports do not contain private keys, seed phrases, or authentication codes
Test Mode Commands
These commands are only available when EIOU_TEST_MODE=true.
out
Process the outgoing message queue (pending transactions).
Syntax:
eiou out
Notes:
- Requires
EIOU_TEST_MODE=trueenvironment variable - Processes pending transactions in the outgoing queue
- Used for testing and debugging
in
Process incoming/held transactions.
Syntax:
eiou in
Notes:
- Requires
EIOU_TEST_MODE=trueenvironment variable - Processes held transactions that may have completed sync
- Used for testing and debugging
Exit Codes
| Code | Description |
|---|---|
0 |
Success |
1 |
Error (see error message for details) |
Rate Limiting
CLI commands are rate-limited per wallet to prevent abuse:
| Command bucket | Limit | Window | Block Duration |
|---|---|---|---|
send |
30 | 60 seconds | 5 minutes |
contact (every eiou contact … subcommand) |
20 | 60 seconds | 5 minutes |
generate |
5 | 5 minutes | 15 minutes |
backup |
10 | 60 seconds | 5 minutes |
chaindrop |
10 | 60 seconds | 5 minutes |
report |
10 | 60 seconds | 5 minutes |
p2p |
30 | 60 seconds | 5 minutes |
request |
20 | 60 seconds | 5 minutes |
| All others | 100 | 60 seconds | 5 minutes |
When rate limited, you’ll see an error with a retry-after time.
See Also
- API Reference - REST API documentation
- API Quick Reference - API endpoint summary
- Error Codes - Complete error code reference