@aeon-ai-pay/aigateway 0.2.3 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,6 +4,26 @@
4
4
  >
5
5
  > **Zero API keys · Zero prepay · x402 protocol pay-per-call · Natural-language driven**
6
6
 
7
+ ---
8
+
9
+ ## 🚀 AEON x BNB Chain: AI Agent Campaign
10
+
11
+ > **Your AI agent is ready to work — now let it pay.**
12
+
13
+ AEON and **BNB Chain** are launching the **AI Agent Campaign**, opening up a native payment rail for autonomous AI agents on BNB Chain. With BNB assets, your agent can now call LLMs, APIs, skills, and compute resources — and settle instantly on-chain.
14
+
15
+ **How it works**
16
+
17
+ Agents pay with BNB-native assets through AEON's infrastructure. Every API call, every model inference, every skill invocation — settled seamlessly, no human in the loop.
18
+
19
+ **🎁 First 1,000 users get $5 USDT in free credits** to start using AEON Skills and experience what agentic commerce actually feels like.
20
+
21
+ Build agents that don't just think — but **transact**.
22
+
23
+ → **[Claim your $5 free credits (Google Form)](https://docs.google.com/forms/d/e/1FAIpQLSe8WF6-Y8Sh2AEC_hEGScyl_gQRahPYWPMDewdXJlfeVENENg/viewform?usp=publish-editor)** · Deploy your agent. Let it run.
24
+
25
+ ---
26
+
7
27
  `@aeon-ai-pay/aigateway` is a unified CLI + Agent Skill. Through a single session-key wallet and the [x402 protocol](https://www.x402.org/), it opens up SkillBoss's 200+ tool capabilities (image / video / audio / search / scraping / email / document / social data / UI generation, etc.) to AI Agents for pay-per-call invocation.
8
28
 
9
29
  ---
package/docs/env-vars.md CHANGED
@@ -4,9 +4,8 @@ All environment variables that affect the `aigateway` CLI. Resolution priority f
4
4
 
5
5
  | Variable | Used by | Default | Purpose |
6
6
  | --- | --- | --- | --- |
7
- | `AIGATEWAY_SERVICE_URL` | All paid commands (`create-card`, `create-image`, `create-card-status`) | `https://ai-api.aeon.xyz` | Override the x402 service base URL. Useful for staging / local backends. |
7
+ | `AIGATEWAY_SERVICE_URL` | All commands that talk to the gateway (`sb invoke`, `sb tools`, `wallet-init`, `wallet-topup`, `wallet-balance`) | `https://ai-api.aeon.xyz` | Override the x402 service base URL. Useful for staging / local backends. |
8
8
  | `EVM_PRIVATE_KEY` | All commands needing a session key | (read from config file) | Override the saved session key. Required when running in custodial / containerised mode where you don't want a config file on disk. **Treat as a secret.** |
9
- | `AICARD_LEGACY_NOOP` | — | — | Reserved. Not currently used. |
10
9
 
11
10
  ## Config file
12
11
 
@@ -26,22 +25,18 @@ All environment variables that affect the `aigateway` CLI. Resolution priority f
26
25
  - `privateKey` / `address` / `mode` — written by `wallet-init` when auto-generating a session key.
27
26
  - `mainWallet` — auto-recorded after a successful `wallet-topup` so `wallet-withdraw` can default to that address.
28
27
 
29
- ## CLI flag priority example
28
+ ## Priority example
30
29
 
31
30
  ```bash
32
- # All four set, --service-url wins
33
- AIGATEWAY_SERVICE_URL=https://env.example.com \
34
- aigateway create-card --amount 5 --service-url=... # (no such flag now — env wins)
35
-
36
- # Only env set
37
- AIGATEWAY_SERVICE_URL=https://staging.example.com \
38
- aigateway create-card --amount 5
31
+ # Env var wins over config file
32
+ AIGATEWAY_SERVICE_URL=https://staging-x402.aeon.xyz \
33
+ aigateway sb invoke --model <id> --inputs '<json>'
39
34
 
40
35
  # Nothing set → built-in default https://ai-api.aeon.xyz
41
- aigateway create-card --amount 5
36
+ aigateway sb invoke --model <id> --inputs '<json>'
42
37
  ```
43
38
 
44
- The `--service-url` CLI flag has been removed in 0.1.0+ — use the env var or edit the config file directly.
39
+ There is no `--service-url` CLI flag — use the env var or edit the config file directly.
45
40
 
46
41
  ## Production hardening
47
42
 
@@ -60,11 +55,14 @@ aigateway wallet-init
60
55
 
61
56
  # Custodial server (key from Vault, no config file)
62
57
  EVM_PRIVATE_KEY=$(vault kv get -field=key merchants/acme-prod) \
63
- aigateway create-card --amount 5 --app-id MERCHANT_ACME_001 --poll
58
+ aigateway sb invoke \
59
+ --model replicate/black-forest-labs/flux-schnell \
60
+ --inputs '{"prompt":"a cyberpunk fox"}' \
61
+ --app-id MERCHANT_ACME_001
64
62
 
65
63
  # Staging
66
64
  AIGATEWAY_SERVICE_URL=https://staging-x402.aeon.xyz \
67
- aigateway create-card --amount 5 --app-id YOUR_TEST_APPID --poll
65
+ aigateway sb tools --category image --app-id YOUR_TEST_APPID
68
66
 
69
67
  # Both
70
68
  AIGATEWAY_SERVICE_URL=https://staging-x402.aeon.xyz \
@@ -6,13 +6,13 @@ The `aigateway` CLI returns a stable exit code that maps to the category of outc
6
6
  | ---: | -------- | ------- |
7
7
  | `0` | Success | Command completed and produced an `ok: true` envelope. |
8
8
  | `1` | User error | Validation, configuration, balance, or user-side rejection. Caller should fix input and retry. |
9
- | `2` | Timeout | Polling, WalletConnect, signature, or on-chain wait exceeded its limit. The underlying operation may still complete asynchronously (e.g. card may still be provisioning). |
9
+ | `2` | Timeout | Polling, WalletConnect, signature, or on-chain wait exceeded its limit. The underlying operation may still complete asynchronously. |
10
10
  | `3` | Service / network | Upstream service unavailable, network error, on-chain revert. Generally retryable after backoff. |
11
11
  | `4` | Internal | Unexpected internal error in the CLI. Please file an issue if reproducible. |
12
12
 
13
13
  ## Error Code Reference
14
14
 
15
- The full set of `error.code` values, grouped by exit code, is defined in [`src/error-codes.mjs`](../src/error-codes.mjs).
15
+ The full set of `error.code` values is defined in [`src/error-codes.mjs`](../src/error-codes.mjs); the table below mirrors that file.
16
16
 
17
17
  ### Exit 1 — User Error
18
18
 
@@ -20,17 +20,25 @@ The full set of `error.code` values, grouped by exit code, is defined in [`src/e
20
20
  | ---- | ---- |
21
21
  | `WALLET_NOT_CONFIGURED` | No local wallet. Run `aigateway wallet-init`. |
22
22
  | `SERVICE_URL_MISSING` | Service URL not configured. |
23
- | `AMOUNT_INVALID` | Amount could not be parsed. |
24
- | `AMOUNT_OUT_OF_RANGE` | Amount outside `amountLimits.min` ~ `amountLimits.max`. |
25
- | `AMOUNT_EXCEEDS_BALANCE` | `withdraw --amount` exceeds available USDT. |
23
+ | `AMOUNT_INVALID` | Amount could not be parsed (e.g. `wallet-topup --amount`, `--topup-amount`). |
24
+ | `AMOUNT_EXCEEDS_BALANCE` | `wallet-withdraw --amount` exceeds available USDT. |
26
25
  | `INSUFFICIENT_USDT` | USDT balance still insufficient after funding. |
27
26
  | `INSUFFICIENT_BNB` | No BNB for approve / withdraw gas. |
28
- | `NO_FUNDS` | Session wallet has zero USDT and zero BNB. |
27
+ | `NO_FUNDS` | Session wallet has zero USDT and zero BNB (withdraw context). |
29
28
  | `NO_MAIN_WALLET` | `wallet-withdraw` invoked without `--to` and no `mainWallet` in config. |
30
- | `MISSING_PROMPT` | `create-image` invoked without `--prompt`. |
31
- | `TOPUP_REQUIRED` | `wallet-topup` / `create-card` / `create-image` running non-TTY with `usdt < 1` and no amount argument. Choose from `error.presets` (5/10/20/50) and rerun (`topup --amount <n>` or pass `--topup-amount <n>` to `create-*`). |
32
- | `TOPUP_AMOUNT_TOO_SMALL` | `topup --amount` (or `create-* --topup-amount`) below `MIN_TOPUP_USDT` (5 USDT) or the per-call minimum (`error.minTopup`). |
29
+ | `MISSING_MODEL` | `sb invoke` invoked without `--model`. |
30
+ | `MISSING_INPUTS` | `sb invoke --inputs` is missing, or required fields are absent. `error.errors[]` lists which. |
31
+ | `INVALID_INPUTS` | Inputs failed schema validation. `error.errors[].kind {enum, type, range}`. |
32
+ | `INVALID_INPUTS_JSON` | `--inputs` could not be parsed as JSON. |
33
+ | `INPUTS_FILE_NOT_FOUND` | `--inputs @path` file does not exist. |
34
+ | `INVALID_MODEL_ID` | Catalog or server rejected the model id. |
35
+ | `CATEGORY_NOT_FOUND` | `sb tools --category` argument not in the live catalog. |
36
+ | `MODEL_PRICING_NOT_CONFIGURED` | Catalog lists the model but the gateway has no price entry yet. |
37
+ | `INVALID_BODY` | Server rejected the request body shape. |
38
+ | `TOPUP_REQUIRED` | Non-TTY context, USDT below the per-call minimum. Choose from `error.presets` (filtered to ≥ `error.minTopup`) and rerun the failing command with `--topup-amount <n>` (or `wallet-topup --amount <n>`). |
39
+ | `TOPUP_AMOUNT_TOO_SMALL` | `--topup-amount` (or `topup --amount`) below `error.minTopup`. |
33
40
  | `PAYMENT_REJECTED` | User rejected the transaction in their wallet. |
41
+ | `WALLET_ERROR` | Generic wallet operation failure (treated as user-resolvable). |
34
42
 
35
43
  ### Exit 2 — Timeout
36
44
 
@@ -38,9 +46,8 @@ The full set of `error.code` values, grouped by exit code, is defined in [`src/e
38
46
  | ---- | ---- |
39
47
  | `PAYMENT_TIMEOUT` | WalletConnect / signature request timed out (5 minutes). |
40
48
  | `WC_SESSION_EXPIRED` | WalletConnect session dropped mid-flow. |
41
- | `POLL_TIMEOUT` | `create-card-status --poll` exhausted attempts. Card may still be provisioning. |
42
- | `TX_TIMEOUT` | On-chain receipt wait exceeded 60 s. |
43
- | `UPDATE_APPLIED` | The CLI just upgraded itself synchronously to a newer version. The previous command was not executed — the caller (or the agent) must rerun it on the new version. Envelope carries `error.from` / `error.to` showing the version transition. |
49
+ | `TX_TIMEOUT` | On-chain receipt wait exceeded its limit. |
50
+ | `UPDATE_APPLIED` | The CLI just upgraded itself synchronously to a newer version. The previous command was **not executed** — the caller (or the agent) must rerun it on the new version. Envelope carries `error.from` / `error.to` showing the version transition. |
44
51
 
45
52
  ### Exit 3 — Service / Network
46
53
 
@@ -48,13 +55,15 @@ The full set of `error.code` values, grouped by exit code, is defined in [`src/e
48
55
  | ---- | ---- |
49
56
  | `SERVICE_UNAVAILABLE` | Generic upstream / network failure. |
50
57
  | `PAYMENT_FETCH_FAILED` | First 402 request to the service failed. |
58
+ | `CATALOG_FETCH_FAILED` | `sb tools` could not fetch the catalog from the server. |
51
59
  | `BALANCE_CHECK_FAILED` | RPC query to BSC failed. |
52
60
  | `ALLOWANCE_CHECK_FAILED` | RPC `allowance()` query failed. |
53
61
  | `TX_REVERTED` | On-chain transaction reverted. |
54
62
  | `WITHDRAW_FAILED` | Withdraw transaction failed (revert / RPC). |
55
- | `APPROVE_FAILED` | `wallet-init` could not broadcast or confirm the facilitator `approve()` tx. |
63
+ | `APPROVE_FAILED` | `wallet-topup` could not broadcast or confirm the facilitator `approve()` tx. |
56
64
  | `FUNDING_FAILED` | WalletConnect funding flow failed (non-timeout / non-reject path). |
57
- | `IMAGE_DOWNLOAD_FAILED` | Generated image URL returned a non-200 / timed out. |
65
+ | `IMAGE_DOWNLOAD_FAILED` | Generated image URL returned a non-200 / timed out. (Legacy alias; `sb invoke` now also emits `DOWNLOAD_FAILED` for non-image artifacts.) |
66
+ | `DOWNLOAD_FAILED` | `sb invoke` could not save a binary artifact (image / video / audio) to disk. The upstream URL is still available in `data.downloaded[].url`. |
58
67
  | `INVALID_PAYMENT_AMOUNT` | Service returned a 402 with `amount === 0`. |
59
68
  | `PAYMENT_FAILED` | Service rejected the signed payment request. |
60
69
 
@@ -63,4 +72,5 @@ The full set of `error.code` values, grouped by exit code, is defined in [`src/e
63
72
  | Code | When |
64
73
  | ---- | ---- |
65
74
  | `INTERNAL_ERROR` | Unexpected error inside the CLI. |
66
- | `WALLET_ERROR` | Generic non-classified WalletConnect failure. (Exit 1 — treated as user-resolvable.) |
75
+
76
+ > Note: `WALLET_ERROR` is defined alongside the timeout block in `error-codes.mjs` but its exit code is `1` (user-resolvable), so it appears under Exit 1 above.
package/docs/ide-setup.md CHANGED
@@ -55,6 +55,6 @@ For Claude Code, OpenClaw, Gemini CLI, GitHub Copilot, and 30+ others, the [skil
55
55
 
56
56
  After installation, in your IDE chat say:
57
57
 
58
- > Create me a $5 virtual card.
58
+ > Generate me an image of a cyberpunk fox.
59
59
 
60
- The agent should propose running `aigateway wallet-init` (one-time, auto-creates a wallet) followed by `aigateway create-card --amount 5 --poll`. If it doesn't, the rule file isn't being picked up — check that the file path matches what your IDE expects and that the IDE has been restarted.
60
+ The agent should propose running `aigateway wallet-init` (one-time, auto-creates a wallet), then `aigateway sb tools --category image` to pick a model, then `aigateway sb invoke --model <id> --inputs '{"prompt":"cyberpunk fox"}'`. If it doesn't, the rule file isn't being picked up — check that the file path matches what your IDE expects and that the IDE has been restarted.
@@ -1,6 +1,6 @@
1
1
  # Output Schema
2
2
 
3
- Every `aigateway` command emits **exactly one line of JSON** to **stdout** —— the *envelope*. Human-readable progress logs go to **stderr** and can be safely ignored by programmatic consumers.
3
+ Every `aigateway` command emits **exactly one line of JSON** to **stdout** the *envelope*. Human-readable progress logs go to **stderr** and can be safely ignored by programmatic consumers.
4
4
 
5
5
  > Pass `--quiet` to suppress non-error stderr. Pass `--legacy-output` to fall back to the pre-envelope shape (see [Legacy mode](#legacy-mode)).
6
6
 
@@ -11,8 +11,8 @@ Every `aigateway` command emits **exactly one line of JSON** to **stdout** —
11
11
  ```json
12
12
  {
13
13
  "ok": true,
14
- "command": "create",
15
- "version": "0.9.0",
14
+ "command": "sb-invoke",
15
+ "version": "x.y.z",
16
16
  "data": { /* command-specific payload */ }
17
17
  }
18
18
  ```
@@ -22,20 +22,21 @@ Every `aigateway` command emits **exactly one line of JSON** to **stdout** —
22
22
  ```json
23
23
  {
24
24
  "ok": false,
25
- "command": "create",
26
- "version": "0.9.0",
25
+ "command": "sb-invoke",
26
+ "version": "x.y.z",
27
27
  "error": {
28
- "code": "AMOUNT_OUT_OF_RANGE",
29
- "message": "Amount must be at least $0.6. Allowed range: $0.6 ~ $800 USD.",
30
- "min": 0.6,
31
- "max": 800
28
+ "code": "MISSING_INPUTS",
29
+ "message": "Inputs validation failed for ...",
30
+ "errors": [{ "field": "prompt", "kind": "missing", "message": "..." }],
31
+ "required": ["prompt"],
32
+ "properties": ["prompt", "aspect_ratio", "num_outputs"]
32
33
  }
33
34
  }
34
35
  ```
35
36
 
36
37
  - `error.code` is a stable identifier from [`src/error-codes.mjs`](../src/error-codes.mjs) — see [exit-codes.md](./exit-codes.md) for the full list.
37
38
  - `error.message` is human-readable and may change between versions; **do not** match on it for control flow.
38
- - Additional fields under `error` are command-specific context (e.g. `min` / `max` / `address` / `required` / `available`).
39
+ - Additional fields under `error` are command-specific context (e.g. `min` / `max` / `address` / `required` / `available` / `errors[]` / `presets`).
39
40
 
40
41
  ## Per-Command `data` Payloads
41
42
 
@@ -49,8 +50,14 @@ Every `aigateway` command emits **exactly one line of JSON** to **stdout** —
49
50
  "mode": "private-key",
50
51
  "address": "0x...",
51
52
  "mainWallet": "0x..." | null,
52
- "serviceUrl": "https://...",
53
- "amountLimits": { "min": 0.6, "max": 800 }
53
+ "usdt": "5.0",
54
+ "bnb": "0.0003",
55
+ "allowance": "115792...max" | "0",
56
+ "needsTopup": false,
57
+ "topupReason": null | "first_time" | "low_balance" | "no_approve" | "chain_check_failed",
58
+ "minTopup": 5,
59
+ "presets": [5, 10, 20, 50],
60
+ "serviceUrl": "https://..."
54
61
  }
55
62
  ```
56
63
 
@@ -70,72 +77,80 @@ Every `aigateway` command emits **exactly one line of JSON** to **stdout** —
70
77
  }
71
78
  ```
72
79
 
73
- ### `create-card`
80
+ ### `sb invoke`
74
81
 
75
82
  ```json
76
83
  {
77
- "appId": "TEST000001",
78
- "orderNo": "...",
79
- "data": { /* sanitized server response */ },
80
- "paymentResponse": { /* decoded PAYMENT-RESPONSE header */ },
81
- "pollResult": { /* present when --poll succeeds */ }
84
+ "model": "replicate/black-forest-labs/flux-schnell",
85
+ "inputs": { "prompt": "...", "aspect_ratio": "1:1" },
86
+ "transaction": "0x..." | null,
87
+ "downloaded": [
88
+ {
89
+ "url": "https://...",
90
+ "localPath": "/home/.../aigateway-images/...png",
91
+ "format": "png",
92
+ "width": 1024,
93
+ "height": 1024,
94
+ "sizeBytes": 412345,
95
+ "sizeHuman": "402.7 KB"
96
+ }
97
+ ],
98
+ "raw": { /* upstream vendor response, unwrapped from { payer, transaction, data } */ },
99
+ "paymentResponse": { "txHash": "0x...", "payer": "0x...", "...": "..." },
100
+ "balance": {
101
+ "initial": "5.0",
102
+ "before": "5.0",
103
+ "after": "4.99",
104
+ "charged": 0.01,
105
+ "topup": null | "5"
106
+ }
82
107
  }
83
108
  ```
84
109
 
85
- ### `create-image`
110
+ - **Binary outputs** (image / video / audio) populate `downloaded[]`. With `--raw` the auto-download is skipped and `downloaded[]` stays empty; the URLs live in `raw`.
111
+ - **JSON-only outputs** (search, scraper, social_data, email, etc.) leave `downloaded` empty; consumers read `raw`.
112
+ - `balance.charged` is the live USDT amount taken for this call (computed server-side as `priceUnit × inputs usage`).
113
+
114
+ Failure shapes carry extra fields per code, e.g.:
86
115
 
87
116
  ```json
88
117
  {
89
- "appId": "TEST000001",
90
- "prompt": "...",
91
- "aspectRatio": "16:9",
92
- "outputFormat": "png",
93
- "model": "...",
94
- "transaction": "0x...",
95
- "images": [
96
- { "url": "https://...", "localPath": "/.../...png", "format": "png", "width": 1024, "height": 576, "sizeBytes": 123456, "sizeHuman": "120.6 KB" }
97
- ],
98
- "balance": { "initial": "5", "before": "5", "after": "4.99", "charged": 0.01, "topup": null }
118
+ "ok": false,
119
+ "command": "sb-invoke",
120
+ "error": {
121
+ "code": "TOPUP_REQUIRED",
122
+ "message": "USDT balance is below the 5 USDT minimum...",
123
+ "minTopup": 5,
124
+ "required": 0.01,
125
+ "currentBalance": "0",
126
+ "address": "0x...",
127
+ "presets": [5, 10, 20, 50],
128
+ "hint": "Rerun: aigateway wallet-topup --amount <usdt> --app-id ..."
129
+ }
99
130
  }
100
131
  ```
101
132
 
102
- **Dry-run (`--dry-run`)** — preflight checks complete but no signing/transaction occurs:
133
+ ### `sb tools`
103
134
 
104
- ```json
105
- {
106
- "dryRun": true,
107
- "url": "...",
108
- "paymentRequirements": { "amountUsdt": 0.66, "amountWei": "660000000000000000", "asset": "0x...", "payTo": "0x...", "orderNo": "..." },
109
- "wallet": { "address": "0x..." },
110
- "decision": { "needTopup": true, "needGas": false, "topupAmount": "0.660000" },
111
- "will": ["fund_usdt_via_walletconnect", "approve_or_skip", "sign_payment_eip712", "submit_to_facilitator", "poll_status"]
112
- }
113
- ```
135
+ `data` shape depends on the filters supplied:
114
136
 
115
- ### `create-card-status`
137
+ | Invocation | `data.mode` | Shape |
138
+ | --- | --- | --- |
139
+ | `sb tools` | (absent) | Full catalog: `{ categories: [{ key, agentTrigger, defaultInputsSchema, models: [...] }], version, ... }` |
140
+ | `sb tools --model <id>` | `"single-model"` | `{ category: "<key>", model: { id, vendor, useCase, price, priceUnit, tier, inputsOverride? }, effectiveSchema: { ... } }` |
141
+ | `sb tools --category <key>` | `"single-category"` | `{ category: { key, agentTrigger, defaultInputsSchema, models: [...] } }` |
142
+ | `sb tools --tier <t>` (alone) | `"tier-filtered"` | Full catalog with each category's `models[]` filtered to `tier === t`, plus `tier: "<t>"` |
116
143
 
117
- ```json
118
- {
119
- "success": true,
120
- "model": {
121
- "orderNo": "...",
122
- "orderStatus": "SUCCESS" | "FAIL" | "PROCESSING" | "...",
123
- "channelStatus": "...",
124
- "cardStatus": "ACTIVE" | "PENDING" | "...",
125
- "cardScheme": "VISA" | "MASTERCARD",
126
- "cardNumber": "•••• 1234",
127
- "...": "(sensitive fields like CVV / expiry are stripped)"
128
- }
129
- }
130
- ```
144
+ `effectiveSchema` = `model.inputsOverride ?? category.defaultInputsSchema` — the JSON-schema-shaped object that `sb invoke` validates against client-side.
131
145
 
132
- ### `wallet`
146
+ ### `wallet-balance`
133
147
 
134
148
  ```json
135
149
  {
136
150
  "mode": "private-key",
137
151
  "address": "0x...",
138
152
  "usdt": "12.34",
153
+ "bnb": "0.0003",
139
154
  "network": "BSC Mainnet (Chain ID: 56)",
140
155
  "mainWallet": { "address": "0x...", "usdt": "..." }
141
156
  }
@@ -182,7 +197,7 @@ Every `aigateway` command emits **exactly one line of JSON** to **stdout** —
182
197
  For consumers still parsing the pre-envelope JSON shape, pass `--legacy-output` to get the old format on stdout (and errors on **stderr** as before):
183
198
 
184
199
  ```bash
185
- aigateway --legacy-output create-card --amount 5
200
+ aigateway --legacy-output wallet-balance
186
201
  ```
187
202
 
188
- Legacy mode is kept for one or two minor releases as a migration aid. New integrations should use the envelope.
203
+ Legacy mode is kept as a migration aid. New integrations should use the envelope.
@@ -1,31 +1,38 @@
1
- # Recipe — Schedule Recurring Card Issuance
1
+ # Recipe — Schedule Recurring Paid Invocations
2
2
 
3
- Use this when an agent needs to issue cards on a schedule for example, "create a $5 card every Monday at 09:00 to seed an autonomous shopping flow."
3
+ > Filename kept for backwards compatibility. The earlier "issue card" workflow has been folded into the unified `aigateway sb invoke` entry point; this recipe now covers any scheduled paid call.
4
+
5
+ Use this when an agent or automation needs to invoke a paid AI tool on a schedule — for example, "generate a marketing image every Monday at 09:00", "transcribe yesterday's recordings nightly", "run a search summarisation every hour".
4
6
 
5
7
  ## Prerequisites
6
8
 
7
9
  1. **Pre-funded session wallet.** WalletConnect requires a browser; cron jobs run headless. Top up the local wallet manually first:
8
10
  ```bash
9
- aigateway wallet-topup --amount 50 # adds USDT + a tiny amount of BNB for approve gas
11
+ aigateway wallet-topup --amount 50 # adds USDT + a tiny amount of BNB for the one-time approve
10
12
  ```
11
- 2. **One-time `approve`.** Run `aigateway create-card --amount 0.6 --poll` once interactively so the approve transaction is on-chain. Subsequent creates won't need WalletConnect again until USDT is depleted.
13
+ 2. **Approve already broadcast.** `wallet-topup` performs the one-time `ERC20.approve(facilitator, MaxUint256)`. After it succeeds, all subsequent `sb invoke` calls are gasless EIP-712 signing no WalletConnect needed until USDT is depleted.
14
+ 3. **Catalog sanity-check.** Before scheduling, run `aigateway sb tools --model <id>` once to confirm the model id is valid and to learn its `effectiveSchema` (so your wrapper builds the correct `--inputs`).
12
15
 
13
16
  ## A Minimal Wrapper Script
14
17
 
15
- `~/bin/issue-card.sh`:
18
+ `~/bin/invoke-tool.sh`:
16
19
 
17
20
  ```bash
18
21
  #!/usr/bin/env bash
19
22
  set -euo pipefail
20
23
 
21
- AMOUNT="${1:-5}"
24
+ MODEL="${1:?model id required}"
25
+ INPUTS_FILE="${2:?path to inputs JSON required}" # e.g. ~/aigateway/jobs/daily-image.json
22
26
  LOG_DIR="${HOME}/.aigateway/logs"
23
27
  mkdir -p "$LOG_DIR"
24
28
  TS=$(date -u +"%Y-%m-%dT%H-%M-%SZ")
25
- LOG="$LOG_DIR/issue-${TS}.log"
29
+ LOG="$LOG_DIR/invoke-${TS}.log"
26
30
 
27
31
  # Capture envelope on stdout; quiet stderr noise
28
- ENVELOPE=$(aigateway --quiet create-card --amount "$AMOUNT" --poll 2>"$LOG")
32
+ ENVELOPE=$(aigateway --quiet sb invoke \
33
+ --model "$MODEL" \
34
+ --inputs "@${INPUTS_FILE}" \
35
+ 2>"$LOG")
29
36
  EXIT=$?
30
37
 
31
38
  echo "$ENVELOPE" > "${LOG%.log}.json"
@@ -37,19 +44,26 @@ if [ "$EXIT" -ne 0 ]; then
37
44
  exit "$EXIT"
38
45
  fi
39
46
 
40
- ORDER=$(echo "$ENVELOPE" | jq -r '.data.orderNo')
41
- echo "[$(date -u)] OK orderNo=$ORDER amount=$AMOUNT"
47
+ TX=$(echo "$ENVELOPE" | jq -r '.data.transaction // "—"')
48
+ FIRST=$(echo "$ENVELOPE" | jq -r '.data.downloaded[0].localPath // empty')
49
+ echo "[$(date -u)] OK tx=$TX file=${FIRST:-n/a} model=$MODEL"
42
50
  ```
43
51
 
44
52
  ```bash
45
- chmod +x ~/bin/issue-card.sh
53
+ chmod +x ~/bin/invoke-tool.sh
46
54
  ```
47
55
 
48
56
  ## Cron Entry
49
57
 
50
58
  ```cron
51
59
  # minute hour dom mon dow command
52
- 0 9 * * 1 /Users/me/bin/issue-card.sh 5 >> /Users/me/.aigateway/logs/cron.log 2>&1
60
+ 0 9 * * 1 /Users/me/bin/invoke-tool.sh replicate/black-forest-labs/flux-schnell /Users/me/aigateway/jobs/weekly-image.json >> /Users/me/.aigateway/logs/cron.log 2>&1
61
+ ```
62
+
63
+ Example `weekly-image.json`:
64
+
65
+ ```json
66
+ { "prompt": "neon city skyline at dusk, hyper-detailed", "aspect_ratio": "16:9" }
53
67
  ```
54
68
 
55
69
  > ⚠️ On macOS, `cron` may lack PATH access to `aigateway`. Use an absolute path (`/Users/me/.nvm/versions/node/v25/bin/aigateway`) or source your shell rc inside the wrapper.
@@ -58,12 +72,16 @@ chmod +x ~/bin/issue-card.sh
58
72
 
59
73
  | Code | Likely cause in cron context | Fix |
60
74
  | ---- | ---------------------------- | --- |
61
- | `INSUFFICIENT_USDT` | Wallet ran dry. | Top up via `aigateway wallet-init` on a workstation. |
62
- | `INSUFFICIENT_BNB` | Approve allowance expired or BNB depleted by retries. | Run `aigateway wallet-gas` to add a small amount. |
63
- | `PAYMENT_TIMEOUT` | WalletConnect was triggered (unexpected should be fully approved). | Run an interactive `aigateway wallet-init` once to refresh allowance. |
64
- | `SERVICE_UNAVAILABLE` | Upstream outage. | Cron will retry next tick. Alert if 3+ consecutive failures. |
75
+ | `INSUFFICIENT_USDT` / `TOPUP_REQUIRED` | Wallet ran dry. Headless cron cannot scan a QR. | Top up via `aigateway wallet-topup --amount <n>` on a workstation. |
76
+ | `INSUFFICIENT_BNB` | BNB depleted (only matters for `wallet-withdraw` / re-approve). | Run `aigateway wallet-gas` interactively on a workstation. |
77
+ | `INVALID_MODEL_ID` | The model id was renamed or removed upstream. | Run `aigateway sb tools` and update the wrapper's `--model`. |
78
+ | `MISSING_INPUTS` / `INVALID_INPUTS` | Inputs file drifted from the schema (e.g. missing `duration_seconds` for video / `duration_minutes` for STT). | Re-pull `sb tools --model <id>` and fix the JSON. |
79
+ | `MODEL_PRICING_NOT_CONFIGURED` | Upstream removed the model from the pricing config. | Pick another model. |
80
+ | `SERVICE_UNAVAILABLE` / `PAYMENT_FETCH_FAILED` | Upstream outage. | Cron will retry next tick. Alert if 3+ consecutive failures. |
81
+ | `PAYMENT_TIMEOUT` | WalletConnect was unexpectedly triggered (should not happen once approve is on-chain). | Run an interactive `aigateway wallet-topup` once to re-fund / re-approve. |
65
82
 
66
83
  ## See Also
67
84
 
68
85
  - [integrate-in-agent.md](./integrate-in-agent.md) — Node.js / Python subprocess wrapper.
69
86
  - [error-recovery.md](./error-recovery.md) — Full code-by-code recovery table.
87
+ - [../output-schema.md](../output-schema.md) — `sb invoke` envelope fields used above (`transaction`, `downloaded[]`, `balance`).
@@ -6,25 +6,40 @@ Map each `error.code` returned by the envelope to a concrete recovery action. Us
6
6
  | ------------ | :--: | -------------------- |
7
7
  | `WALLET_NOT_CONFIGURED` | 1 | Run `aigateway wallet-init` once (auto-creates a local session wallet). |
8
8
  | `SERVICE_URL_MISSING` | 1 | Override via env `AIGATEWAY_SERVICE_URL`. The default service URL is wired into the CLI for production; this should never trigger in normal use. |
9
- | `AMOUNT_INVALID` | 1 | Caller bug — input must be a numeric string. |
10
- | `AMOUNT_OUT_OF_RANGE` | 1 | Re-prompt user with `error.min` ~ `error.max`. Do **not** silently clamp. |
11
- | `AMOUNT_EXCEEDS_BALANCE` | 1 | Use the smaller of requested vs. `error.available`. |
12
- | `INSUFFICIENT_USDT` | 1 | Top-up failed or partial. Surface `error.required` / `error.available` to user, ask whether to retry with a new amount. |
13
- | `INSUFFICIENT_BNB` | 1 | Run `aigateway wallet-gas` to top up a small amount of BNB via WalletConnect, then retry. |
14
- | `NO_FUNDS` | 1 | Nothing to withdraw. Inform the user, possibly suggest `wallet-topup`. |
15
- | `NO_MAIN_WALLET` | 1 | Caller must pass `--to <address>`. |
9
+ | `AMOUNT_INVALID` | 1 | Caller bug — input must be a positive numeric string (used by `wallet-topup`, `wallet-gas`, `wallet-withdraw`, `--topup-amount`). |
10
+ | `AMOUNT_EXCEEDS_BALANCE` | 1 | `wallet-withdraw --amount` exceeded available USDT. Use the smaller of requested vs. `error.available`. |
11
+ | `INSUFFICIENT_USDT` | 1 | Top-up failed or the chosen `--topup-amount` was still below the call's required USDT. Surface `error.required` / `error.available`; ask the user to retry with a larger top-up. |
12
+ | `INSUFFICIENT_BNB` | 1 | Approve / withdraw needs BNB for gas. Run `aigateway wallet-gas` (WalletConnect, must be interactive), then retry. |
13
+ | `NO_FUNDS` | 1 | Nothing to withdraw. Inform the user; suggest `wallet-topup` if relevant. |
14
+ | `NO_MAIN_WALLET` | 1 | `wallet-withdraw` invoked with no `mainWallet` saved. Re-run with `--to <address>`. |
15
+ | `MISSING_MODEL` | 1 | `sb invoke --model` is required. Run `aigateway sb tools` to pick one. |
16
+ | `MISSING_INPUTS` | 1 | `sb invoke --inputs` is required, or the JSON is missing required fields. `error.errors[]` lists which fields are missing; `error.required[]` lists all required keys for the model. |
17
+ | `INVALID_INPUTS` | 1 | Inputs failed schema validation. `error.errors[]` items carry `{ field, kind, message }` where `kind ∈ {enum, type, range}`. Fix and retry. |
18
+ | `INVALID_INPUTS_JSON` | 1 | `--inputs` could not be parsed as JSON. Check quoting / escaping; on shells use `JSON.stringify(...)` from your wrapper. |
19
+ | `INPUTS_FILE_NOT_FOUND` | 1 | `--inputs @path` file does not exist. Resolve to an absolute path or correct the caller. |
20
+ | `INVALID_MODEL_ID` | 1 | Server / catalog rejected the model id. Run `aigateway sb tools --category <key>` to find a valid one. |
21
+ | `CATEGORY_NOT_FOUND` | 1 | `sb tools --category` argument is not in the live catalog. Run `aigateway sb tools` (no filter) to list categories. |
22
+ | `MODEL_PRICING_NOT_CONFIGURED` | 1 | The catalog lists the model but the gateway has no price entry yet. Pick another model or ask the operator to add it. |
23
+ | `INVALID_BODY` | 1 | Server rejected the request body shape. Usually a CLI / catalog drift; file a bug. |
24
+ | `TOPUP_REQUIRED` | 1 | Non-TTY context, USDT below the per-call minimum. Choose from `error.presets` (filtered to ≥ `error.minTopup`) and rerun the failing command with `--topup-amount <n>`. |
25
+ | `TOPUP_AMOUNT_TOO_SMALL` | 1 | `--topup-amount` (or `topup --amount`) below `error.minTopup`. Rerun with a larger value. |
16
26
  | `PAYMENT_REJECTED` | 1 | User cancelled in their wallet. **Do not auto-retry** — ask user first. |
17
- | `PAYMENT_TIMEOUT` | 2 | WalletConnect approval expired (5 min). Ask user whether to retry. **Do not auto-retry.** |
18
- | `WC_SESSION_EXPIRED` | 2 | Reconnect required. Re-run the original command. |
19
- | `POLL_TIMEOUT` | 2 | Card may still provision. Surface `error.orderNo` and query later with `aigateway create-card-status --order-no <n>`. |
20
- | `TX_TIMEOUT` | 2 | The on-chain transfer is likely still pending query the chain or retry the status command. |
27
+ | `PAYMENT_TIMEOUT` | 2 | WalletConnect approval window expired (5 min). Ask user whether to retry. **Do not auto-retry.** |
28
+ | `WC_SESSION_EXPIRED` | 2 | WalletConnect relay dropped the session. Re-run the original command. |
29
+ | `TX_TIMEOUT` | 2 | The on-chain transfer is likely still pending. Wait, then re-check with `wallet-balance`. |
30
+ | `UPDATE_APPLIED` | 2 | CLI just upgraded itself synchronously. The previous command was **not executed**. Surface `error.from` `error.to` and **rerun the same command verbatim** on the new version. |
21
31
  | `SERVICE_UNAVAILABLE` | 3 | Exponential backoff: 1 s → 4 s → 16 s, max 3 attempts. |
22
- | `PAYMENT_FETCH_FAILED` | 3 | Same as above. Check network connectivity. |
32
+ | `PAYMENT_FETCH_FAILED` | 3 | First 402 probe failed. Backoff + retry; check network connectivity. |
33
+ | `CATALOG_FETCH_FAILED` | 3 | `sb tools` could not reach the server. Retry once; if it persists, `sb invoke` still runs (server-side validation is the safety net). |
23
34
  | `BALANCE_CHECK_FAILED` | 3 | BSC RPC hiccup. Retry once after 2 s. |
35
+ | `ALLOWANCE_CHECK_FAILED` | 3 | BSC RPC hiccup. Retry once after 2 s. |
24
36
  | `TX_REVERTED` | 3 | On-chain failure. Capture `error.message` for diagnosis; do not retry blindly. |
25
37
  | `WITHDRAW_FAILED` | 3 | Withdraw transaction failed. Check `aigateway wallet-balance` and retry. |
38
+ | `APPROVE_FAILED` | 3 | One-time facilitator approve failed during `wallet-topup`. Inspect the tx; retry the top-up. |
26
39
  | `INVALID_PAYMENT_AMOUNT` | 3 | Server-side issue (returned amount = 0). Retry after a short delay. |
27
- | `PAYMENT_FAILED` | 3 | Service rejected the signed request. Surface `error.data` to the user / log. |
40
+ | `PAYMENT_FAILED` | 3 | Service rejected the signed payment request. Surface `error.data` / `error.status` to the user / log. On 5xx, retry once. |
41
+ | `IMAGE_DOWNLOAD_FAILED` / `DOWNLOAD_FAILED` | 3 | The paid call succeeded but the local download failed. The original URL is still in the upstream response — surface it from `data.downloaded[].url` (when available) or re-fetch via `--raw`. **Do not re-invoke the model** (you'd pay again). |
42
+ | `FUNDING_FAILED` | 3 | Non-timeout / non-reject failure in the WalletConnect funding flow. Re-run `wallet-topup`. |
28
43
  | `INTERNAL_ERROR` | 4 | File a bug. Don't retry. |
29
44
  | `WALLET_ERROR` | 1 | Generic wallet failure. Surface to user, ask whether to retry. |
30
45
 
@@ -41,13 +56,29 @@ async function withRetry(fn, { codes, attempts = 3, baseDelayMs = 1000 } = {}) {
41
56
  }
42
57
 
43
58
  // Only retry transient service/network errors
44
- await withRetry(() => runAEON AI Gateway(["create", "--amount", "5", "--poll"]), {
45
- codes: ["SERVICE_UNAVAILABLE", "PAYMENT_FETCH_FAILED", "BALANCE_CHECK_FAILED", "INVALID_PAYMENT_AMOUNT"],
46
- });
59
+ await withRetry(
60
+ () => runAigateway([
61
+ "sb", "invoke",
62
+ "--model", "replicate/black-forest-labs/flux-schnell",
63
+ "--inputs", JSON.stringify({ prompt: "a cyberpunk fox" }),
64
+ ]),
65
+ {
66
+ codes: [
67
+ "SERVICE_UNAVAILABLE",
68
+ "PAYMENT_FETCH_FAILED",
69
+ "CATALOG_FETCH_FAILED",
70
+ "BALANCE_CHECK_FAILED",
71
+ "ALLOWANCE_CHECK_FAILED",
72
+ "INVALID_PAYMENT_AMOUNT",
73
+ ],
74
+ },
75
+ );
47
76
  ```
48
77
 
49
78
  ## Anti-patterns
50
79
 
51
80
  - ❌ Don't retry `PAYMENT_REJECTED` or `PAYMENT_TIMEOUT` automatically — the user actively cancelled or walked away.
81
+ - ❌ Don't retry `IMAGE_DOWNLOAD_FAILED` / `DOWNLOAD_FAILED` by re-invoking the model — the paid call already settled, you'd be charged again. Re-fetch the URL or re-run with `--raw`.
52
82
  - ❌ Don't match on `error.message` text — messages may change between versions. Match on `error.code`.
53
83
  - ❌ Don't ignore exit code in favour of envelope. Stack-level proxies sometimes mangle stdout; the exit code is a redundant safety net.
84
+ - ❌ Don't paper over `UPDATE_APPLIED` by treating it as a generic timeout — it's a "new binary; rerun me" signal, not a failure.