# ELTEX Agentic Wallet API

Agentic Wallet binds one versioned USDC policy to one agent identity and one dedicated ELTEX API key. It supports autonomous, policy-controlled x402 payments and direct USDC transfers on Base and Solana while keeping private keys, seed phrases, Thirdweb project secrets, user JWTs, and unrestricted signing authority away from agents.

## Owner setup

Complete this once in **Dashboard → Agentic Wallet → Agents & Policies**:

1. Create or reuse an agent identity. This identity is shared with Agent State.
2. Open **API Keys** and create a dedicated key with **Agentic Wallet** enabled.
3. Create a grant that binds that exact agent and key.
4. Choose Base and/or Solana, USDC limits, optional approval thresholds, expiry, optional x402 domains, and optional direct-transfer recipient restrictions.
5. For Base, select **Authorize Base**, enter the email OTP, then activate the grant. For Solana, fund the user-specific allocation address with USDC and enough SOL for fees, then activate the grant.

Creating an agent does not grant wallet access. Editing a grant creates a new immutable policy version and returns the grant to pending authorization. Pause or revoke releases unsubmitted reservations. A revoked grant cannot be reactivated.

## Authentication and scopes

Send the dedicated key as `Authorization: Bearer ...`:

- `wallet:read`: read the assigned grant, policy, balance, and reserved USDC.
- `wallet:spend`: preflight or request a policy-controlled x402 payment or direct USDC transfer.

The key must be the exact active key selected in the grant. OAuth tokens and unbound API keys are rejected on Agentic Wallet routes.

## Endpoint summary

```text
GET  /v1/agentic-wallet/balance?agent_id={agent_id}
POST /v1/agentic-wallet/preflight
POST /v1/agentic-wallet/x402/fetch
POST /v1/agentic-wallet/transfer
```

Dashboard-only owner operations use Firebase authentication under `/api/agentic-wallet`: create agents and grants, start/complete Base authorization, activate/pause/revoke grants, and approve/reject payments. The Base authorization routes are `POST /api/agentic-wallet/grants/{grant_id}/base-authorization/start` and `/complete`; the dashboard handles these for the owner.

## Use cases and service discovery

Open **Dashboard → Agentic Wallet → Use Cases** to browse common patterns and a cached aggregation of reachable public x402 catalogs. Typical purchases include research and onchain data, web extraction, model inference, media generation, MCP tools, RPC, storage, proxies, verification, and paywalled digital content.

For live discovery, clients can query public facilitator catalogs directly, including:

```text
GET https://api.cdp.coinbase.com/platform/v2/x402/discovery/resources
GET https://api.cdp.coinbase.com/platform/v2/x402/discovery/search?query={encoded_query}
GET https://facilitator.payai.network/discovery/resources
```

Eltex also exposes one normalized, read-only directory across CDP Bazaar, PayAI Bazaar, x402-list, x402list.fun, Agentic.Market, Pay.sh, x402scan-sourced listings, and the Ampersend directory record:

```http
GET /v1/x402/services?q=image&network=base&source=all&limit=100&offset=0
```

No wallet credential is sent to any directory. The response contains `services`, `directories`, per-source health in `sources`, and `pagination`. Valid `network` shortcuts are `all`, `mainnet`, `base`, and `solana`; `source` accepts a directory ID returned in `directories`. Exact endpoint records have `callable: true`. Provider-level directory records have `callable: false` and must be opened and resolved to a current endpoint before payment.

When the runtime cannot connect directly to CDP, Eltex loads Bazaar-provenance records through the public x402-list mirror and marks the CDP source with `fallback: true`. x402scan-provenance records use the same machine-readable mirror. Ampersend listings require an authorized Ampersend session, so Eltex links that directory but never forwards, scrapes, or stores a user's Ampersend credentials.

Catalog entries are unverified discovery metadata, not Eltex endorsements or payment authorizations. Before paying, read the resource documentation and obtain a fresh HTTP `402` response from the exact HTTPS URL. Confirm the method, input schema, x402 version, scheme, network, canonical USDC asset, amount, recipient, and timeout. Then use the smallest suitable `maxValue`; the active grant and the live 402 response remain authoritative.

## Read balance and policy

```http
GET /v1/agentic-wallet/balance?agent_id=agt_...
Authorization: Bearer $ELTEX_API_KEY
```

The response contains `grant`, `balance`, and `reservedUsdc`. `balance` reports canonical USDC separately for Base and Solana. `reservedUsdc` includes pending approval, authorized, and submitting requests so an agent cannot race the daily or monthly policy limit.

## Preflight

```http
POST /v1/agentic-wallet/preflight
Authorization: Bearer $ELTEX_API_KEY
Idempotency-Key: stable-logical-action-id
Content-Type: application/json

{
  "agentId": "agt_...",
  "kind": "x402",
  "network": "base",
  "amount": "0.10",
  "resourceUrl": "https://api.example.com/paid-resource",
  "method": "GET"
}
```

Preflight validates and reserves the exact action or creates a human approval. Prefer `/x402/fetch` for the complete x402 negotiation and payment flow, or `/transfer` for a direct USDC send to an explicit policy recipient.

## Direct USDC transfer

```http
POST /v1/agentic-wallet/transfer
Authorization: Bearer $ELTEX_API_KEY
Idempotency-Key: stable-logical-transfer-id
Content-Type: application/json

{
  "agentId": "agt_...",
  "network": "base",
  "to": "0x1111111111111111111111111111111111111111",
  "amount": "0.10"
}
```

The implementation accepts `destination` as an alias for `to`. Direct transfers require `permissions.transfer=true` and a valid `to`/`destination` address on the selected network. `allowedRecipients` is optional: an empty list lets the caller choose any valid address at send time, while a non-empty list restricts the destination to those exact entries. Base comparisons are case-insensitive, while Solana addresses remain case-sensitive. The response is normally `submitting` with a Thirdweb transaction id. Keep the same idempotency key and inspect Agentic Wallet activity until the provider result is reconciled; do not create a second payment while the first is `submitting`.

## Request an x402 resource

```http
POST /v1/agentic-wallet/x402/fetch
Authorization: Bearer $ELTEX_API_KEY
Idempotency-Key: stable-logical-payment-id
Content-Type: application/json

{
  "agentId": "agt_...",
  "network": "base",
  "url": "https://api.example.com/paid-resource",
  "method": "GET",
  "maxValue": "0.10",
  "body": null
}
```

`maxValue` is a conservative USDC cap with at most six decimals. The request is authorized only when the grant is active and unexpired, bound to the credential, permits x402 on the selected network, matches any configured domain restriction, and has sufficient per-transaction, daily, and monthly capacity.

For Base, ELTEX negotiates both current x402 v2 (`PAYMENT-REQUIRED`/`PAYMENT-SIGNATURE`) and legacy v1 responses. v2 exact USDC challenges are signed by the already OTP-authorized Thirdweb User Wallet enclave session; no custom-auth plan, server wallet, seed phrase, or agent-held signer is involved. Legacy providers that call the network `base` are retried without a forced CAIP-2 `chainId` only after Thirdweb confirms that the same canonical USDC asset is accepted on Base. The `scheme` is selected from the live 402 challenge, not sent as an unsupported fetch query parameter. Solana continues through Thirdweb's hosted x402 flow.

Before paying, always verify the fresh challenge's URL, exact scheme, CAIP-2 network, canonical USDC asset, amount, recipient, and timeout. ELTEX rejects a v2 challenge that does not match the requested resource, Base network, canonical Base USDC, or the policy cap.

An empty domain list allows all public HTTPS destinations by default. Exact names and explicit wildcard subdomains narrow access. HTTPS is mandatory; URLs containing credentials and local, private, link-local, multicast, or unresolved destinations are rejected.

Every effectful request requires a stable portable `Idempotency-Key`. The key is bound to the agent, network, amount cap, URL, method, and request-body digest. Reusing it with the identical request returns the existing execution. Reusing it for a different request returns `409 idempotency_key_conflict`.

## Human approval and execution states

When a policy requires approval, the first x402 or direct-transfer request returns:

```json
{
  "ok": true,
  "approvalRequired": true,
  "execution": { "id": "awx_...", "status": "awaiting_approval" }
}
```

The owner approves the exact action in **Dashboard → Agentic Wallet → Approvals**. The agent then retries the identical request with the identical idempotency key. An approval or individual execution authorization expires after ten minutes. This is separate from wallet grant authorization: the default policy is autonomous below its configured approval threshold, and `requireEveryPaymentApproval` can be enabled when a human checkpoint is desired.

Execution states are `awaiting_approval`, `authorized`, `submitting`, `confirmed`, `rejected`, `failed`, `expired`, and `cancelled`. A verified repeat of a confirmed request returns `replayed: true`. If the Thirdweb result is indeterminate after submission, the execution stays `submitting` for reconciliation and cannot be paid again with a new logical attempt.

## Policy enforcement

The active immutable policy controls:

- permitted networks (`base`, `solana`) and `x402` permission;
- maximum USDC per transaction, per day, and per month;
- autonomous execution below a configured approval threshold, or approval for every payment when explicitly enabled;
- all public HTTPS domains by default, or a narrowed exact/wildcard list;
- direct transfers validate the requested address, with optional exact `allowedRecipients` restrictions;
- grant expiry, pause, revocation, and credential binding.

Do not split one logical purchase into multiple requests to evade a limit or approval. Never switch agent, key, network, URL, or destination to bypass a denial.

## Execution readiness

Policy configuration and execution readiness are separate:

- Base spends from that user's Thirdweb User Wallet. The owner authorizes each grant by email OTP. ELTEX encrypts the resulting grant session at rest and no longer imposes an artificial 24-hour cap. If Thirdweb includes an expiry in its user JWT, that provider expiry (or the grant's own expiry) remains authoritative; if neither expires, the grant stays authorized until the owner pauses/revokes or edits the policy. ELTEX never returns the session to the agent.
- Solana spends from the distinct Thirdweb project-managed allocation wallet created for that ELTEX user. It is not a shared treasury. Fund that address with canonical Solana USDC and enough SOL for transaction fees.

The dashboard reports each network's readiness. A grant cannot activate until every selected network is ready. Stop on `spending_authorization_required`; do not substitute another wallet or credential.

## Errors

Error responses use the normal ELTEX envelope and include `X-Request-ID`. Common codes include:

| HTTP | Code | Action |
|---:|---|---|
| 400 | `idempotency_key_required`, `amount_invalid`, `wallet_action_invalid`, `x402_method_invalid`, `recipient_invalid` | Correct the request; do not retry unchanged. |
| 401 | `invalid_api_key` | Stop and obtain a valid dedicated key. |
| 403 | `dedicated_key_required`, `wallet_grant_missing`, `wallet_grant_inactive`, `wallet_grant_expired` | Stop; the owner must correct the binding or grant state. |
| 403 | `network_not_allowed`, `action_not_allowed`, `x402_domain_not_allowed`, `recipient_not_allowed` | Respect the policy; do not route around it. `recipient_not_allowed` applies only when the owner configured recipient restrictions. |
| 403 | `transaction_limit_exceeded`, `daily_limit_exceeded`, `monthly_limit_exceeded` | Stop or ask the owner to change the policy. |
| 409 | `idempotency_key_conflict`, `payment_not_authorized`, `payment_authorization_expired`, `payment_submission_in_progress`, `transfer_not_authorized`, `transfer_authorization_expired`, `transfer_submission_in_progress` | Reuse the same key only for the same live logical action; wait when submission is already in progress. |
| 409 | `spending_authorization_required` | Ask the owner to complete network authorization or allocation. |
| 422 | `x402_payment_cap_exceeded`, `x402_payment_method_unsupported`, `x402_resource_mismatch`, `x402_requirements_invalid`, `thirdweb_request_failed` | Do not retry unchanged. Re-check the live 402 challenge, cap, network, asset, and scheme. |
| 502/503 | `thirdweb_signer_failed`, `thirdweb_signer_unavailable`, `thirdweb_x402_payment_rejected`, `thirdweb_unavailable`, `x402_resource_unavailable` | Keep the same idempotency key and retry only after the provider/resource recovers; an execution marked `submitting` must be reconciled first. |

Never include API keys, wallet secrets, private keys, seed phrases, or Thirdweb secrets in logs, Agent State, error reports, or support messages.
