@aexhq/sdk 0.40.6 → 0.40.8
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 +159 -159
- package/dist/_contracts/asset-upload-helper.d.ts +38 -0
- package/dist/_contracts/asset-upload-helper.js +111 -0
- package/dist/_contracts/internal.d.ts +5 -9
- package/dist/_contracts/internal.js +5 -79
- package/dist/_contracts/operations.d.ts +9 -2
- package/dist/_contracts/operations.js +141 -16
- package/dist/_contracts/retry-core.d.ts +27 -0
- package/dist/_contracts/retry-core.js +75 -0
- package/dist/_contracts/runtime-types.d.ts +6 -0
- package/dist/_contracts/stable.d.ts +10 -5
- package/dist/_contracts/stable.js +10 -5
- package/dist/asset-upload.d.ts +2 -1
- package/dist/asset-upload.js +28 -61
- package/dist/asset-upload.js.map +1 -1
- package/dist/cli.mjs +297 -80
- package/dist/cli.mjs.sha256 +1 -1
- package/dist/client.d.ts +5 -0
- package/dist/client.js +8 -13
- package/dist/client.js.map +1 -1
- package/dist/retry.js +13 -41
- package/dist/retry.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/docs/authentication.md +125 -125
- package/docs/billing.md +118 -118
- package/docs/concepts/agent-tools.md +66 -66
- package/docs/concepts/composition.md +37 -37
- package/docs/concepts/providers-and-runtimes.md +54 -54
- package/docs/concepts/runs.md +49 -49
- package/docs/concepts/subagents.md +88 -88
- package/docs/credentials.md +125 -125
- package/docs/defaults.md +64 -64
- package/docs/errors.md +196 -196
- package/docs/events.md +243 -243
- package/docs/limits-and-quotas.md +144 -144
- package/docs/limits.md +50 -50
- package/docs/mcp.md +44 -44
- package/docs/networking.md +163 -163
- package/docs/outputs.md +267 -267
- package/docs/public-surface.json +77 -77
- package/docs/quickstart.md +119 -119
- package/docs/release.md +38 -38
- package/docs/retries.md +129 -129
- package/docs/run-config.md +58 -58
- package/docs/run-record.md +55 -55
- package/docs/secrets.md +125 -125
- package/docs/testing.md +35 -35
- package/docs/vision-skills.md +91 -91
- package/docs/webhooks.md +127 -127
- package/examples/feature-tour.ts +282 -282
- package/examples/spike-settle-latency.ts +125 -125
- package/package.json +1 -1
package/docs/authentication.md
CHANGED
|
@@ -1,125 +1,125 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Authentication
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# Authentication
|
|
6
|
-
|
|
7
|
-
Every SDK and CLI call authenticates with an **aex API key**: a bearer
|
|
8
|
-
credential that is **workspace-scoped** — the workspace is derived server-side
|
|
9
|
-
from the token, so there is no workspace parameter anywhere in the API. A
|
|
10
|
-
request either carries a valid token for a workspace or it is rejected with
|
|
11
|
-
`401 unauthorized` (see [Errors](errors.md)).
|
|
12
|
-
|
|
13
|
-
## Getting a token (invite-only beta)
|
|
14
|
-
|
|
15
|
-
aex is currently in **invite-only beta**. Workspaces and their initial API
|
|
16
|
-
tokens are provisioned by the aex team — contact <support@aex.dev> for beta
|
|
17
|
-
access. Once your workspace exists, you can create and delete additional tokens
|
|
18
|
-
in the dashboard at <https://aex.dev>.
|
|
19
|
-
|
|
20
|
-
## Using a token
|
|
21
|
-
|
|
22
|
-
Pass the token to the SDK constructor, the CLI's `--api-key` flag, or persist
|
|
23
|
-
it once with `aex login`:
|
|
24
|
-
|
|
25
|
-
```ts
|
|
26
|
-
import { Aex } from "@aexhq/sdk";
|
|
27
|
-
|
|
28
|
-
const aex = new Aex(process.env.AEX_API_KEY!);
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
```bash
|
|
32
|
-
npx aex whoami --api-key "$AEX_API_KEY"
|
|
33
|
-
|
|
34
|
-
# or persist it once, then omit --api-key on later commands:
|
|
35
|
-
npx aex login --api-key "$AEX_API_KEY"
|
|
36
|
-
npx aex whoami
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
(`new Aex(apiKey)` is the canonical constructor; the equivalent options form is
|
|
40
|
-
documented once in [Credentials](credentials.md).)
|
|
41
|
-
|
|
42
|
-
The token travels as a standard `Authorization: Bearer` header. Treat it like
|
|
43
|
-
any other secret: keep it in environment variables or a secret manager, never
|
|
44
|
-
in run config, prompts, or committed files.
|
|
45
|
-
|
|
46
|
-
## Plane routing and the `baseUrl` guard
|
|
47
|
-
|
|
48
|
-
An aex API key is **self-describing**: it embeds the plane (`dev` / `prd`) and
|
|
49
|
-
region it was minted for. The constructor parses the key and routes accordingly,
|
|
50
|
-
with **zero network**:
|
|
51
|
-
|
|
52
|
-
- **Omit `baseUrl`** and
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
- **Supply a `baseUrl` whose plane disagrees with the key** (e.g. a `dev` key
|
|
56
|
-
pointed at `https://api.aex.dev`) and the constructor throws
|
|
57
|
-
`CredentialValidationError` **before any request** — you no longer discover the
|
|
58
|
-
mismatch as a late `401 token_invalid` after a full round-trip.
|
|
59
|
-
|
|
60
|
-
```ts
|
|
61
|
-
// prd key → routes to https://api.aex.dev automatically:
|
|
62
|
-
const prd = new Aex(process.env.AEX_PRD_KEY!);
|
|
63
|
-
|
|
64
|
-
// dev key →
|
|
65
|
-
const dev = new Aex(process.env.AEX_DEV_KEY
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
## Scopes
|
|
69
|
-
|
|
70
|
-
A token carries a set of **scopes**; every API route requires one, and a token
|
|
71
|
-
that lacks the route's scope fails with `403 insufficient_scope` naming the
|
|
72
|
-
missing scope. The customer-grantable scopes:
|
|
73
|
-
|
|
74
|
-
| Scope | Grants |
|
|
75
|
-
| --- | --- |
|
|
76
|
-
| `runs:read` | Read sessions/runs, their events and event archives, and webhook delivery ledgers. |
|
|
77
|
-
| `runs:write` | Open sessions, send turns, submit runs, suspend/resume, redeliver webhooks, reveal the webhook signing secret. |
|
|
78
|
-
| `runs:cancel` | Cancel a session/run. |
|
|
79
|
-
| `runs:delete` | Delete a session/run record. |
|
|
80
|
-
| `outputs:read` | List, read, download, and mint links for captured outputs. |
|
|
81
|
-
| `files:write` | Upload asset bytes (files, skills, AGENTS.md) staged for a run. |
|
|
82
|
-
| `files:delete` | Delete workspace asset-store entries. |
|
|
83
|
-
| `secrets:read` | List workspace secrets and read their metadata (never values). |
|
|
84
|
-
| `secrets:write` | Create, rotate, and delete workspace secrets. |
|
|
85
|
-
| `mcp:read` | List and read workspace MCP server configurations. |
|
|
86
|
-
| `mcp:write` | Create workspace MCP server configurations. |
|
|
87
|
-
| `mcp:delete` | Delete workspace MCP server configurations. |
|
|
88
|
-
| `billing:read` | Read billing state and create hosted billing sessions. |
|
|
89
|
-
| `workspaces:delete` | Owner self-service workspace hard-erase. |
|
|
90
|
-
|
|
91
|
-
Tokens may additionally carry the reserved scopes `skills:read` /
|
|
92
|
-
`skills:write` / `skills:delete`, `agentsmd:read` / `agentsmd:write` /
|
|
93
|
-
`agentsmd:delete`, and `files:read`. No API route requires them today — skill
|
|
94
|
-
and AGENTS.md asset uploads are covered by `files:write` — so treat them as
|
|
95
|
-
inert placeholders for future per-asset-type routes.
|
|
96
|
-
|
|
97
|
-
A typical automation token carries `runs:read`, `runs:write`, and
|
|
98
|
-
`outputs:read`. Grant the rest only where the workload needs them — a read-only
|
|
99
|
-
reporting token, for example, needs no `runs:write`.
|
|
100
|
-
|
|
101
|
-
## Introspection: `whoami`
|
|
102
|
-
|
|
103
|
-
`aex.whoami()` (CLI: `aex whoami`) validates the token and returns the
|
|
104
|
-
workspace id, the token's scopes, and — on current platform deployments — a
|
|
105
|
-
`limits` object with the workspace's effective admission caps
|
|
106
|
-
(`maxConcurrentRuns`, `submitRatePerMinute`, `spendCapUsd`, `monthSpendUsd`,
|
|
107
|
-
`balanceUsd`, `balanceGraceFloorUsd`, `paymentMethodStatus`), resolved by the
|
|
108
|
-
same code the submit gates enforce. Use it as a cheap credential check and to
|
|
109
|
-
anticipate `429`/`402` rejections before submitting — see
|
|
110
|
-
[Limits & quotas](limits-and-quotas.md) and [Errors](errors.md).
|
|
111
|
-
|
|
112
|
-
## Rotation and revocation
|
|
113
|
-
|
|
114
|
-
- **Rotate** by creating a new token in the dashboard, switching your
|
|
115
|
-
deployment to it, then deleting the old one. Tokens are independent — both
|
|
116
|
-
stay valid during the switch, so rotation needs no downtime.
|
|
117
|
-
- **Revoke** by deleting the token in the dashboard; deletion takes effect
|
|
118
|
-
immediately (allow up to a minute for in-flight caches to expire).
|
|
119
|
-
- Token create/delete are rate-limited per workspace (see
|
|
120
|
-
[Limits & quotas](limits-and-quotas.md)).
|
|
121
|
-
- If you cannot reach the dashboard (or suspect workspace-level compromise),
|
|
122
|
-
contact <support@aex.dev>.
|
|
123
|
-
|
|
124
|
-
Provider keys (`apiKeys`) and runtime secrets are a separate, per-call surface —
|
|
125
|
-
see [Credentials](credentials.md) and [Secrets](secrets.md).
|
|
1
|
+
---
|
|
2
|
+
title: Authentication
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Authentication
|
|
6
|
+
|
|
7
|
+
Every SDK and CLI call authenticates with an **aex API key**: a bearer
|
|
8
|
+
credential that is **workspace-scoped** — the workspace is derived server-side
|
|
9
|
+
from the token, so there is no workspace parameter anywhere in the API. A
|
|
10
|
+
request either carries a valid token for a workspace or it is rejected with
|
|
11
|
+
`401 unauthorized` (see [Errors](errors.md)).
|
|
12
|
+
|
|
13
|
+
## Getting a token (invite-only beta)
|
|
14
|
+
|
|
15
|
+
aex is currently in **invite-only beta**. Workspaces and their initial API
|
|
16
|
+
tokens are provisioned by the aex team — contact <support@aex.dev> for beta
|
|
17
|
+
access. Once your workspace exists, you can create and delete additional tokens
|
|
18
|
+
in the dashboard at <https://aex.dev>.
|
|
19
|
+
|
|
20
|
+
## Using a token
|
|
21
|
+
|
|
22
|
+
Pass the token to the SDK constructor, the CLI's `--api-key` flag, or persist
|
|
23
|
+
it once with `aex login`:
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import { Aex } from "@aexhq/sdk";
|
|
27
|
+
|
|
28
|
+
const aex = new Aex(process.env.AEX_API_KEY!);
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npx aex whoami --api-key "$AEX_API_KEY"
|
|
33
|
+
|
|
34
|
+
# or persist it once, then omit --api-key on later commands:
|
|
35
|
+
npx aex login --api-key "$AEX_API_KEY"
|
|
36
|
+
npx aex whoami
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
(`new Aex(apiKey)` is the canonical constructor; the equivalent options form is
|
|
40
|
+
documented once in [Credentials](credentials.md).)
|
|
41
|
+
|
|
42
|
+
The token travels as a standard `Authorization: Bearer` header. Treat it like
|
|
43
|
+
any other secret: keep it in environment variables or a secret manager, never
|
|
44
|
+
in run config, prompts, or committed files.
|
|
45
|
+
|
|
46
|
+
## Plane routing and the `baseUrl` guard
|
|
47
|
+
|
|
48
|
+
An aex API key is **self-describing**: it embeds the plane (`dev` / `prd`) and
|
|
49
|
+
region it was minted for. The constructor parses the key and routes accordingly,
|
|
50
|
+
with **zero network**:
|
|
51
|
+
|
|
52
|
+
- **Omit `baseUrl`** and the key routes to its canonical hosted API plane:
|
|
53
|
+
`prd` keys route to `https://api.aex.dev`, and `dev` keys route to
|
|
54
|
+
`https://dev-api.aex.dev`.
|
|
55
|
+
- **Supply a `baseUrl` whose plane disagrees with the key** (e.g. a `dev` key
|
|
56
|
+
pointed at `https://api.aex.dev`) and the constructor throws
|
|
57
|
+
`CredentialValidationError` **before any request** — you no longer discover the
|
|
58
|
+
mismatch as a late `401 token_invalid` after a full round-trip.
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
// prd key → routes to https://api.aex.dev automatically:
|
|
62
|
+
const prd = new Aex(process.env.AEX_PRD_KEY!);
|
|
63
|
+
|
|
64
|
+
// dev key → routes to https://dev-api.aex.dev automatically:
|
|
65
|
+
const dev = new Aex(process.env.AEX_DEV_KEY!);
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Scopes
|
|
69
|
+
|
|
70
|
+
A token carries a set of **scopes**; every API route requires one, and a token
|
|
71
|
+
that lacks the route's scope fails with `403 insufficient_scope` naming the
|
|
72
|
+
missing scope. The customer-grantable scopes:
|
|
73
|
+
|
|
74
|
+
| Scope | Grants |
|
|
75
|
+
| --- | --- |
|
|
76
|
+
| `runs:read` | Read sessions/runs, their events and event archives, and webhook delivery ledgers. |
|
|
77
|
+
| `runs:write` | Open sessions, send turns, submit runs, suspend/resume, redeliver webhooks, reveal the webhook signing secret. |
|
|
78
|
+
| `runs:cancel` | Cancel a session/run. |
|
|
79
|
+
| `runs:delete` | Delete a session/run record. |
|
|
80
|
+
| `outputs:read` | List, read, download, and mint links for captured outputs. |
|
|
81
|
+
| `files:write` | Upload asset bytes (files, skills, AGENTS.md) staged for a run. |
|
|
82
|
+
| `files:delete` | Delete workspace asset-store entries. |
|
|
83
|
+
| `secrets:read` | List workspace secrets and read their metadata (never values). |
|
|
84
|
+
| `secrets:write` | Create, rotate, and delete workspace secrets. |
|
|
85
|
+
| `mcp:read` | List and read workspace MCP server configurations. |
|
|
86
|
+
| `mcp:write` | Create workspace MCP server configurations. |
|
|
87
|
+
| `mcp:delete` | Delete workspace MCP server configurations. |
|
|
88
|
+
| `billing:read` | Read billing state and create hosted billing sessions. |
|
|
89
|
+
| `workspaces:delete` | Owner self-service workspace hard-erase. |
|
|
90
|
+
|
|
91
|
+
Tokens may additionally carry the reserved scopes `skills:read` /
|
|
92
|
+
`skills:write` / `skills:delete`, `agentsmd:read` / `agentsmd:write` /
|
|
93
|
+
`agentsmd:delete`, and `files:read`. No API route requires them today — skill
|
|
94
|
+
and AGENTS.md asset uploads are covered by `files:write` — so treat them as
|
|
95
|
+
inert placeholders for future per-asset-type routes.
|
|
96
|
+
|
|
97
|
+
A typical automation token carries `runs:read`, `runs:write`, and
|
|
98
|
+
`outputs:read`. Grant the rest only where the workload needs them — a read-only
|
|
99
|
+
reporting token, for example, needs no `runs:write`.
|
|
100
|
+
|
|
101
|
+
## Introspection: `whoami`
|
|
102
|
+
|
|
103
|
+
`aex.whoami()` (CLI: `aex whoami`) validates the token and returns the
|
|
104
|
+
workspace id, the token's scopes, and — on current platform deployments — a
|
|
105
|
+
`limits` object with the workspace's effective admission caps
|
|
106
|
+
(`maxConcurrentRuns`, `submitRatePerMinute`, `spendCapUsd`, `monthSpendUsd`,
|
|
107
|
+
`balanceUsd`, `balanceGraceFloorUsd`, `paymentMethodStatus`), resolved by the
|
|
108
|
+
same code the submit gates enforce. Use it as a cheap credential check and to
|
|
109
|
+
anticipate `429`/`402` rejections before submitting — see
|
|
110
|
+
[Limits & quotas](limits-and-quotas.md) and [Errors](errors.md).
|
|
111
|
+
|
|
112
|
+
## Rotation and revocation
|
|
113
|
+
|
|
114
|
+
- **Rotate** by creating a new token in the dashboard, switching your
|
|
115
|
+
deployment to it, then deleting the old one. Tokens are independent — both
|
|
116
|
+
stay valid during the switch, so rotation needs no downtime.
|
|
117
|
+
- **Revoke** by deleting the token in the dashboard; deletion takes effect
|
|
118
|
+
immediately (allow up to a minute for in-flight caches to expire).
|
|
119
|
+
- Token create/delete are rate-limited per workspace (see
|
|
120
|
+
[Limits & quotas](limits-and-quotas.md)).
|
|
121
|
+
- If you cannot reach the dashboard (or suspect workspace-level compromise),
|
|
122
|
+
contact <support@aex.dev>.
|
|
123
|
+
|
|
124
|
+
Provider keys (`apiKeys`) and runtime secrets are a separate, per-call surface —
|
|
125
|
+
see [Credentials](credentials.md) and [Secrets](secrets.md).
|
package/docs/billing.md
CHANGED
|
@@ -1,118 +1,118 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Billing & webhook signing secret
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# Billing & webhook signing secret
|
|
6
|
-
|
|
7
|
-
Workspace-level billing, subscription, and webhook verification calls are
|
|
8
|
-
token-scoped like every other client call — the workspace is derived
|
|
9
|
-
server-side from the API key.
|
|
10
|
-
|
|
11
|
-
The billing reads — `aex.billing()`, `aex.billingLedger()`, and the CLI
|
|
12
|
-
`aex billing` (and its `ledger` sub-verb) — require the **`billing:read`**
|
|
13
|
-
scope; a token without it fails with `403 insufficient_scope` (see
|
|
14
|
-
[Errors](errors.md)). This is why the [Quickstart](quickstart.md) mints
|
|
15
|
-
`billing:read` alongside `runs:read` / `runs:write` / `outputs:read`.
|
|
16
|
-
|
|
17
|
-
## Read the billing summary
|
|
18
|
-
|
|
19
|
-
`aex.billing()` returns the workspace's prepaid balance, current-month spend,
|
|
20
|
-
and the spend cap enforced on new runs, plus plan fields:
|
|
21
|
-
|
|
22
|
-
```ts
|
|
23
|
-
import { Aex } from "@aexhq/sdk";
|
|
24
|
-
|
|
25
|
-
const aex = new Aex(process.env.AEX_API_KEY!);
|
|
26
|
-
const billing = await aex.billing();
|
|
27
|
-
console.log(billing.balanceUsd, billing.monthSpendUsd, billing.spendCapUsd);
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
The returned `BillingSummary` is additive-tolerant: fields a newer deployment
|
|
31
|
-
reports that this SDK version does not know yet pass through on the object
|
|
32
|
-
instead of being rejected.
|
|
33
|
-
|
|
34
|
-
CLI equivalent:
|
|
35
|
-
|
|
36
|
-
```bash
|
|
37
|
-
aex billing # human-readable balance / month spend / spend cap
|
|
38
|
-
aex billing --json # the raw wire body for scripting
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
## Manage the subscription
|
|
42
|
-
|
|
43
|
-
`aex.billingCheckout({ planKey })` creates a hosted checkout session for a paid
|
|
44
|
-
plan. Open the returned URL in a browser; the workspace plan changes after
|
|
45
|
-
checkout completes and the hosted API confirms the subscription.
|
|
46
|
-
|
|
47
|
-
```ts
|
|
48
|
-
const { url } = await aex.billingCheckout({
|
|
49
|
-
planKey: "pro",
|
|
50
|
-
idempotencyKey: crypto.randomUUID()
|
|
51
|
-
});
|
|
52
|
-
console.log(url);
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
`aex.billingPortal()` creates a hosted billing portal session for the workspace:
|
|
56
|
-
|
|
57
|
-
```ts
|
|
58
|
-
const { url } = await aex.billingPortal({ returnUrl: "https://aex.dev/billing" });
|
|
59
|
-
console.log(url);
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
CLI equivalents:
|
|
63
|
-
|
|
64
|
-
```bash
|
|
65
|
-
aex billing upgrade pro
|
|
66
|
-
aex billing portal
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
## Read the credit ledger
|
|
70
|
-
|
|
71
|
-
`aex.billingLedger({ limit })` returns recent credit-ledger rows, newest first —
|
|
72
|
-
allowance grants, adjustments, and run charges with signed `amountUsd` (credits
|
|
73
|
-
positive, charges negative). `limit` is clamped server-side to [1, 100] (default
|
|
74
|
-
25); the read is not cursor-paged.
|
|
75
|
-
|
|
76
|
-
```ts
|
|
77
|
-
const { entries } = await aex.billingLedger({ limit: 50 });
|
|
78
|
-
for (const entry of entries) {
|
|
79
|
-
console.log(entry.createdAt, entry.entryType, entry.amountUsd);
|
|
80
|
-
}
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
CLI equivalent:
|
|
84
|
-
|
|
85
|
-
```bash
|
|
86
|
-
aex billing ledger --limit 50 # JSON rows, newest first
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
## Reveal the webhook signing secret
|
|
90
|
-
|
|
91
|
-
Run webhooks are signed Standard-Webhooks style with a per-workspace secret.
|
|
92
|
-
`aex.webhookSigningSecret()` reveals it (creating one on first use) as the
|
|
93
|
-
`whsec_<base64>` string that `verifyAexWebhook` takes as `secret`:
|
|
94
|
-
|
|
95
|
-
```ts
|
|
96
|
-
import { Aex, verifyAexWebhook } from "@aexhq/sdk";
|
|
97
|
-
|
|
98
|
-
const aex = new Aex(process.env.AEX_API_KEY!);
|
|
99
|
-
const { whsec } = await aex.webhookSigningSecret();
|
|
100
|
-
|
|
101
|
-
// In your webhook receiver:
|
|
102
|
-
const verified = await verifyAexWebhook({
|
|
103
|
-
rawBody, // the exact request body bytes as a string
|
|
104
|
-
headers, // the inbound request headers
|
|
105
|
-
secret: whsec
|
|
106
|
-
});
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
Repeat calls return the SAME value — the hosted API does not rotate the
|
|
110
|
-
signing secret. Treat the reveal as sensitive: store it in your secret manager
|
|
111
|
-
and never log it.
|
|
112
|
-
|
|
113
|
-
CLI equivalent (prints the bare `whsec_...` string, pipeable into a secret
|
|
114
|
-
store; the reveal never goes to stderr or debug traces):
|
|
115
|
-
|
|
116
|
-
```bash
|
|
117
|
-
aex webhooks secret
|
|
118
|
-
```
|
|
1
|
+
---
|
|
2
|
+
title: Billing & webhook signing secret
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Billing & webhook signing secret
|
|
6
|
+
|
|
7
|
+
Workspace-level billing, subscription, and webhook verification calls are
|
|
8
|
+
token-scoped like every other client call — the workspace is derived
|
|
9
|
+
server-side from the API key.
|
|
10
|
+
|
|
11
|
+
The billing reads — `aex.billing()`, `aex.billingLedger()`, and the CLI
|
|
12
|
+
`aex billing` (and its `ledger` sub-verb) — require the **`billing:read`**
|
|
13
|
+
scope; a token without it fails with `403 insufficient_scope` (see
|
|
14
|
+
[Errors](errors.md)). This is why the [Quickstart](quickstart.md) mints
|
|
15
|
+
`billing:read` alongside `runs:read` / `runs:write` / `outputs:read`.
|
|
16
|
+
|
|
17
|
+
## Read the billing summary
|
|
18
|
+
|
|
19
|
+
`aex.billing()` returns the workspace's prepaid balance, current-month spend,
|
|
20
|
+
and the spend cap enforced on new runs, plus plan fields:
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
import { Aex } from "@aexhq/sdk";
|
|
24
|
+
|
|
25
|
+
const aex = new Aex(process.env.AEX_API_KEY!);
|
|
26
|
+
const billing = await aex.billing();
|
|
27
|
+
console.log(billing.balanceUsd, billing.monthSpendUsd, billing.spendCapUsd);
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The returned `BillingSummary` is additive-tolerant: fields a newer deployment
|
|
31
|
+
reports that this SDK version does not know yet pass through on the object
|
|
32
|
+
instead of being rejected.
|
|
33
|
+
|
|
34
|
+
CLI equivalent:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
aex billing # human-readable balance / month spend / spend cap
|
|
38
|
+
aex billing --json # the raw wire body for scripting
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Manage the subscription
|
|
42
|
+
|
|
43
|
+
`aex.billingCheckout({ planKey })` creates a hosted checkout session for a paid
|
|
44
|
+
plan. Open the returned URL in a browser; the workspace plan changes after
|
|
45
|
+
checkout completes and the hosted API confirms the subscription.
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
const { url } = await aex.billingCheckout({
|
|
49
|
+
planKey: "pro",
|
|
50
|
+
idempotencyKey: crypto.randomUUID()
|
|
51
|
+
});
|
|
52
|
+
console.log(url);
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
`aex.billingPortal()` creates a hosted billing portal session for the workspace:
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
const { url } = await aex.billingPortal({ returnUrl: "https://aex.dev/billing" });
|
|
59
|
+
console.log(url);
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
CLI equivalents:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
aex billing upgrade pro
|
|
66
|
+
aex billing portal
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Read the credit ledger
|
|
70
|
+
|
|
71
|
+
`aex.billingLedger({ limit })` returns recent credit-ledger rows, newest first —
|
|
72
|
+
allowance grants, adjustments, and run charges with signed `amountUsd` (credits
|
|
73
|
+
positive, charges negative). `limit` is clamped server-side to [1, 100] (default
|
|
74
|
+
25); the read is not cursor-paged.
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
const { entries } = await aex.billingLedger({ limit: 50 });
|
|
78
|
+
for (const entry of entries) {
|
|
79
|
+
console.log(entry.createdAt, entry.entryType, entry.amountUsd);
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
CLI equivalent:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
aex billing ledger --limit 50 # JSON rows, newest first
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Reveal the webhook signing secret
|
|
90
|
+
|
|
91
|
+
Run webhooks are signed Standard-Webhooks style with a per-workspace secret.
|
|
92
|
+
`aex.webhookSigningSecret()` reveals it (creating one on first use) as the
|
|
93
|
+
`whsec_<base64>` string that `verifyAexWebhook` takes as `secret`:
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
import { Aex, verifyAexWebhook } from "@aexhq/sdk";
|
|
97
|
+
|
|
98
|
+
const aex = new Aex(process.env.AEX_API_KEY!);
|
|
99
|
+
const { whsec } = await aex.webhookSigningSecret();
|
|
100
|
+
|
|
101
|
+
// In your webhook receiver:
|
|
102
|
+
const verified = await verifyAexWebhook({
|
|
103
|
+
rawBody, // the exact request body bytes as a string
|
|
104
|
+
headers, // the inbound request headers
|
|
105
|
+
secret: whsec
|
|
106
|
+
});
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Repeat calls return the SAME value — the hosted API does not rotate the
|
|
110
|
+
signing secret. Treat the reveal as sensitive: store it in your secret manager
|
|
111
|
+
and never log it.
|
|
112
|
+
|
|
113
|
+
CLI equivalent (prints the bare `whsec_...` string, pipeable into a secret
|
|
114
|
+
store; the reveal never goes to stderr or debug traces):
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
aex webhooks secret
|
|
118
|
+
```
|
|
@@ -1,66 +1,66 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Agent tools
|
|
3
|
-
description: The default builtin tools available inside managed runs.
|
|
4
|
-
icon: TerminalSquare
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
Managed runs inject the complete builtin tool set into the agent by default:
|
|
8
|
-
|
|
9
|
-
- `bash`, `code_execution` — run shell commands / model-written snippets
|
|
10
|
-
- `read_file`, `write_file`, `edit_file` — file read/create/patch
|
|
11
|
-
- `grep`, `glob` — search file contents and paths
|
|
12
|
-
- `head`, `tail` — read bounded file slices
|
|
13
|
-
- `ls`, `stat`, `wc` — list a directory, inspect path metadata, count lines/words/bytes
|
|
14
|
-
- `web_fetch`, `web_search` — fetch a URL / managed web search
|
|
15
|
-
- `todo_write` — maintain a todo list
|
|
16
|
-
- `subagent`, `subagent_result` — delegate to and read back from child runs (see [Subagents](subagents.md))
|
|
17
|
-
- `bash_output`, `bash_kill` — manage background bash jobs
|
|
18
|
-
- `wait`, `git` — bounded idle-yield and first-class git
|
|
19
|
-
|
|
20
|
-
## Toggling builtins
|
|
21
|
-
|
|
22
|
-
Set `includeBuiltinTools: false` to inject NO builtins — useful for a pure-MCP
|
|
23
|
-
or pure-custom run where every tool comes from `mcpServers` or `tools`.
|
|
24
|
-
|
|
25
|
-
`includeBuiltinTools` defaults to `true`.
|
|
26
|
-
|
|
27
|
-
## Cherry-picking builtins
|
|
28
|
-
|
|
29
|
-
The `tools` list accepts both custom tool bundles and BUILTIN tool references
|
|
30
|
-
(bare name strings, preferably `BuiltinTools.<name>`). Use builtin references
|
|
31
|
-
to pick a narrow subset alongside `includeBuiltinTools: false`.
|
|
32
|
-
|
|
33
|
-
The final tool list is ordered: resolved builtin tools, then custom tools, then
|
|
34
|
-
MCP tools.
|
|
35
|
-
|
|
36
|
-
## Custom tools
|
|
37
|
-
|
|
38
|
-
Attach your own tool in `tools` as a bundle built with `Tool.fromFiles(...)` (an
|
|
39
|
-
explicit `{ entry, files }`) or `Tool.fromPath(dir)` (a directory with a
|
|
40
|
-
`tool.json` at its root). The bundle's **entry must be a JS module** — a
|
|
41
|
-
`.js`/`.mjs`/`.cjs` file present in the bundle that **default-exports a function
|
|
42
|
-
or an object with an `execute` method**. This is validated at authoring time, so
|
|
43
|
-
a non-JS entry (e.g. a `run.sh`) is rejected right where you build the tool, not
|
|
44
|
-
opaquely mid-run when the runtime's module loader would fail to import it.
|
|
45
|
-
|
|
46
|
-
Networking is open by default within the platform's managed egress ceiling and
|
|
47
|
-
a fixed SSRF deny-list. `web_fetch` and `web_search` reach the network over a
|
|
48
|
-
managed, SSRF-guarded path that is **not** governed by `environment.networking`,
|
|
49
|
-
so their hosts never need to be listed in a `limited` allowlist. Setting
|
|
50
|
-
`environment.networking.mode` to `limited` restricts only the agent's own
|
|
51
|
-
arbitrary egress (e.g. a `curl` in `bash`); the built-in web tools keep working.
|
|
52
|
-
See [Networking](../networking.md) for the full two-layer model.
|
|
53
|
-
|
|
54
|
-
## Disable builtins
|
|
55
|
-
|
|
56
|
-
```ts
|
|
57
|
-
import { Models } from "@aexhq/sdk";
|
|
58
|
-
|
|
59
|
-
await aex.run({
|
|
60
|
-
model: Models.CLAUDE_HAIKU_4_5,
|
|
61
|
-
message: "Use only the declared MCP tools.",
|
|
62
|
-
mcpServers,
|
|
63
|
-
includeBuiltinTools: false,
|
|
64
|
-
apiKeys: { anthropic: process.env.ANTHROPIC_API_KEY! }
|
|
65
|
-
});
|
|
66
|
-
```
|
|
1
|
+
---
|
|
2
|
+
title: Agent tools
|
|
3
|
+
description: The default builtin tools available inside managed runs.
|
|
4
|
+
icon: TerminalSquare
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Managed runs inject the complete builtin tool set into the agent by default:
|
|
8
|
+
|
|
9
|
+
- `bash`, `code_execution` — run shell commands / model-written snippets
|
|
10
|
+
- `read_file`, `write_file`, `edit_file` — file read/create/patch
|
|
11
|
+
- `grep`, `glob` — search file contents and paths
|
|
12
|
+
- `head`, `tail` — read bounded file slices
|
|
13
|
+
- `ls`, `stat`, `wc` — list a directory, inspect path metadata, count lines/words/bytes
|
|
14
|
+
- `web_fetch`, `web_search` — fetch a URL / managed web search
|
|
15
|
+
- `todo_write` — maintain a todo list
|
|
16
|
+
- `subagent`, `subagent_result` — delegate to and read back from child runs (see [Subagents](subagents.md))
|
|
17
|
+
- `bash_output`, `bash_kill` — manage background bash jobs
|
|
18
|
+
- `wait`, `git` — bounded idle-yield and first-class git
|
|
19
|
+
|
|
20
|
+
## Toggling builtins
|
|
21
|
+
|
|
22
|
+
Set `includeBuiltinTools: false` to inject NO builtins — useful for a pure-MCP
|
|
23
|
+
or pure-custom run where every tool comes from `mcpServers` or `tools`.
|
|
24
|
+
|
|
25
|
+
`includeBuiltinTools` defaults to `true`.
|
|
26
|
+
|
|
27
|
+
## Cherry-picking builtins
|
|
28
|
+
|
|
29
|
+
The `tools` list accepts both custom tool bundles and BUILTIN tool references
|
|
30
|
+
(bare name strings, preferably `BuiltinTools.<name>`). Use builtin references
|
|
31
|
+
to pick a narrow subset alongside `includeBuiltinTools: false`.
|
|
32
|
+
|
|
33
|
+
The final tool list is ordered: resolved builtin tools, then custom tools, then
|
|
34
|
+
MCP tools.
|
|
35
|
+
|
|
36
|
+
## Custom tools
|
|
37
|
+
|
|
38
|
+
Attach your own tool in `tools` as a bundle built with `Tool.fromFiles(...)` (an
|
|
39
|
+
explicit `{ entry, files }`) or `Tool.fromPath(dir)` (a directory with a
|
|
40
|
+
`tool.json` at its root). The bundle's **entry must be a JS module** — a
|
|
41
|
+
`.js`/`.mjs`/`.cjs` file present in the bundle that **default-exports a function
|
|
42
|
+
or an object with an `execute` method**. This is validated at authoring time, so
|
|
43
|
+
a non-JS entry (e.g. a `run.sh`) is rejected right where you build the tool, not
|
|
44
|
+
opaquely mid-run when the runtime's module loader would fail to import it.
|
|
45
|
+
|
|
46
|
+
Networking is open by default within the platform's managed egress ceiling and
|
|
47
|
+
a fixed SSRF deny-list. `web_fetch` and `web_search` reach the network over a
|
|
48
|
+
managed, SSRF-guarded path that is **not** governed by `environment.networking`,
|
|
49
|
+
so their hosts never need to be listed in a `limited` allowlist. Setting
|
|
50
|
+
`environment.networking.mode` to `limited` restricts only the agent's own
|
|
51
|
+
arbitrary egress (e.g. a `curl` in `bash`); the built-in web tools keep working.
|
|
52
|
+
See [Networking](../networking.md) for the full two-layer model.
|
|
53
|
+
|
|
54
|
+
## Disable builtins
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
import { Models } from "@aexhq/sdk";
|
|
58
|
+
|
|
59
|
+
await aex.run({
|
|
60
|
+
model: Models.CLAUDE_HAIKU_4_5,
|
|
61
|
+
message: "Use only the declared MCP tools.",
|
|
62
|
+
mcpServers,
|
|
63
|
+
includeBuiltinTools: false,
|
|
64
|
+
apiKeys: { anthropic: process.env.ANTHROPIC_API_KEY! }
|
|
65
|
+
});
|
|
66
|
+
```
|