> ## Documentation Index
> Fetch the complete documentation index at: https://docs.metalntwx.com/llms.txt
> Use this file to discover all available pages before exploring further.

# metal-agent Reference

> Every metal-agent command, its flags and what it prints, the MCP server's tools, and what a mandate enforces

`metal-agent` is the CLI and MCP server of the `@metalntwx/metal-agent`
npm package:

```bash theme={null}
npm install -g @metalntwx/metal-agent@0.3.3
```

Commands print `name value` lines, one per line. A failure prints
`error: <message>` to stderr and exits 1; `pull` also exits 1 on a refusal,
3 on `pending` and 4 on `held`, and `verify` exits 1 on a failed check. Amounts are decimal
`*USDZ`; amounts under a mandate are in `*USDZ`, to the cent.
`metal-agent --version` prints the installed version alone on one line.

## CLI

Every command that reads or writes the chain takes these flags:

| Flag | Sets |
| - | - |
| `--network testnet` | The network. Required by every command but `key` and `mcp`. |
| `--rpc-url <url>` | An [endpoint](https://docs.metalntwx.com/network/endpoints.md) of your own; overrides `METAL_RPC_URL`. `status`, `account create` and every `mandate` command but `credential create` need one on testnet. |
| `--faucet-url <url>` | Another faucet; overrides `METAL_FAUCET_URL`. |
| `--facilitator-url <url>` | Another facilitator for `mandate pull`; overrides `METAL_FACILITATOR_URL`. |
| `--factory <address>` | Another account factory for `account create` and `mandate bind`, `replace`, `renew`, `revoke`, `status` and `verify`; the network's by default. |

### Keys and funds

#### key create

Generates the agent's key and writes its key file. Refuses to
overwrite one.

```bash theme={null}
metal-agent key create [--out <file>]
```

| Flag | Sets |
| - | - |
| `--out` | The key file to write; `~/.metal-agent/key.json` by default. |

Prints `address` and `keyfile`.

#### key import

Writes a key you already hold to the key file. Takes a hex key, with or
without `0x`, a file holding one, or a key file.

```bash theme={null}
metal-agent key import <file|hex> [--out <file>]
```

Prints `address` and `keyfile`, never the key. Like `key create`, it does
not overwrite a key file.

#### fund

Asks the testnet faucet to fund an address; the faucet sets the amount.
The faucet limits every client behind one IP address together, so a
refusal of this client names the Faucet page in the Metal console, which
grants per signed-in user.

```bash theme={null}
metal-agent fund <address> --network testnet
```

Prints `funded`, `transaction` and `explorer`, or reports an address that
already holds a full grant. An IP address gets ten grants a UTC day, one a
minute, out of the faucet's 1,000 a day for every client; a
`client_rate_limited` error names the seconds to wait.

### Paying

#### pay

Requests a URL. If it answers `402` with an `exact` offer in `*USDZ`, signs
the payment with the key file, retries, and prints the settlement, the
response headers and the body.

```bash theme={null}
metal-agent pay <url> --network testnet [--key <file>] [--max <usdz>]
  [--method <method>] [--body <text>] [--header 'name: value']...
```

| Flag | Sets |
| - | - |
| `--key` | The key file to pay from; `~/.metal-agent/key.json` by default. |
| `--max` | The most one payment may cost; 1 `*USDZ` by default. A higher offer is refused before signing. |
| `--method` | The HTTP method; GET by default, POST when there is a `--body`. |
| `--body` | The request body, sent as `application/json` unless a `--header` names a content type. |
| `--header` | A request header, repeatable. Sent again with the payment. |

Prints `nonce` as soon as the payment is signed, then `status`, `payer`,
`payee`, `amount`, `network`, `transaction` and `explorer`, then one
`header <name>: <value>` line per response header, except those it hides
such as `content-type`, `date` and CORS headers. `body` comes last. Under a mandate, `mandate <mandate id>`
comes first. A refusal exits with one of three prefixes:

| Error | Meaning |
| - | - |
| `payment refused before signing: …` | The offer is above `--max`, in another token, or for another EIP-712 domain. Nothing was signed. |
| `payment refused: <reason>` | The facilitator refused at verification, and the [reason](https://docs.metalntwx.com/agents/facilitator.md#refusal-reasons) names why; or the seller's own check refused, in its words. Ends `nothing was paid`. |
| `payment refused at settlement: <reason>` | The facilitator refused at settlement for a [reason](https://docs.metalntwx.com/agents/facilitator.md#refusal-reasons) that moves nothing, with the transaction hash when there is one. Ends `nothing was paid`. |

An offer with no `exact` option on the network named fails before signing
with `Failed to create payment payload: …`; one on another network names it,
as `the offer is on testnet (eip155:63825), not devnet (eip155:1337)`. These
errors, and a seller that cannot be reached, end `nothing was signed`.

If the answer to a signed payment is lost, or the seller fails or answers
`409` after it, the error says `a payment was signed and may have settled`.
`payment in doubt at settlement: <reason>` means the same: any failed
settlement whose reason is not one that moves nothing, such as
`settlement_in_doubt`, `already_settled` or a seller's own `fetch failed`
when the facilitator's answer to it was lost. Before paying again, look for
it in the facilitator's `/settlements?payTo=<payee>`, by an id ending in the
`nonce` line printed first; `<payee>` is the `payTo` of the seller's `402`
offer, in its base64 JSON `payment-required` header. A seller that answers
without a settlement prints `payment unconfirmed`; one that answers with a
settlement prints it, whatever its status. A paid request redirected to
another origin is not followed, so no other site receives the payment;
`status` and `header location` show where it points.

#### pay under a mandate

Pays from the owner's account under a mandate, signed by the mandate key.
The mandate's limits apply in place of `--max` and `--key`, which the
command refuses.

```bash theme={null}
metal-agent pay <url> --mandate <credential> --network testnet [--mandate-key-file <file>]
```

| Flag | Sets |
| - | - |
| `--mandate` | The credential file. |
| `--mandate-key-file` | The mandate key file; by default the `.key.json` file in the credential's directory whose key the credential names. |

Prints `mandate`, then the same lines as `pay`, with `payer` the owner's
account. When the seller's `402` asks for a signed order, prints
`signed-offer <text>`. An offer the mandate cannot pay, such as one in
another token or not a whole number of cents, fails before signing with
`Failed to create payment payload: …`. A payment
outside the mandate exits with
`payment refused: mandate_…`; the [reasons](#what-a-mandate-enforces) are
below.

#### status

Shows a settlement from chain data.

```bash theme={null}
metal-agent status <txHash> --network testnet --rpc-url <url>
```

Prints `transaction`, `status`, `block`, `submitter`, `gas` and one
`transfer <amount> from <address> to <address>` line per transfer the
transaction carried.

### Spending limits

#### account create

Creates the owner's Metal account on chain, the one a mandate's
`--principal` is. The owner key pays the gas; one that holds too little is
funded first, from the faucet on testnet. An account that exists is named, and
nothing is sent.

```bash theme={null}
metal-agent account create --out <file> --network testnet --rpc-url <url>
metal-agent account create --key <file> --network testnet --rpc-url <url>
```

| Flag | Sets |
| - | - |
| `--out` | The owner key file, created when it does not exist. |
| `--key` | An owner key file that exists. One of the two is required. |

Prints `account`, `owner` and `keyfile`, `funded` when it funds the owner
key, then `deployed` and the deployment's `transaction`, `explorer` and `gas`.
When a later step fails, such as a faucet refusal, the error says why and
names the key file, which is kept; the same command continues from it.

#### mandate credential create

Writes a credential stating a mandate's limits, and beside it the mandate
key the agent signs with.

```bash theme={null}
metal-agent mandate credential create --principal <address> --cap <usdz> --budget <usdz> \
  --out <file> --key <file> | --issuer-key <file> --network testnet \
  [--payee <address>[,<name>[,<website>]]]... \
  [--expires-in <seconds>] [--starts-in <seconds>] [--max-occurrences <n>] [--description <text>] [--mandate-key-file <file>]
```

| Flag | Sets |
| - | - |
| `--principal` | The owner's account, which the agent pays from. |
| `--cap` | The most one payment may be. |
| `--budget` | The most all payments may add up to over the mandate's life. It never resets. |
| `--out` | The credential file to write; for `mandate.json`, the mandate key goes in `mandate.key.json`. |
| `--payee` | An address the agent may pay, with an optional name and website after it, comma-separated; repeatable. Name none and it may pay any address. |
| `--expires-in` | The mandate's life in seconds; 30 days by default. |
| `--starts-in` | Seconds from now until the mandate starts; by default it starts at 00:00 UTC on the day it is issued. |
| `--max-occurrences` | The most payments the agent may make; unlimited by default. |
| `--description` | What the mandate is for; `mandate status` shows it. |
| `--key` | The owner's key file. The keys that sign the credential live beside it, created on first use: for `owner-key.json`, in `owner-key.issuer.json`. |
| `--issuer-key` | An issuer key file to sign with instead of the one beside `--key`. |
| `--mandate-key-file` | A mandate key file that exists, to name again, as a replacement does. |

Prints `credential` and `mandate`, the terms (`description`,
`principal`, `mandate-key`, `token`, `per-payment-cap`, `budget`, `starts`, `expiry`,
`max-occurrences` when it is set, and `payee` per address, with its name
and website, or `payees any`), then `mandate-key-file`, `issuer-key-file`
and `issuer-public-file`.

#### mandate bind

Records the mandate on the owner's account, signed by the account's
owners. The account must exist already; `account create` creates a
one-owner one.

```bash theme={null}
metal-agent mandate bind --credential <file> --key <file> --network testnet --rpc-url <url> \
  [--signer-key <file>]... [--issuer <file>]...
```

| Flag | Sets |
| - | - |
| `--credential` | The credential file. |
| `--key` | The owner key file. Pays the gas and is the sole signer unless `--signer-key` names the owners who sign. |
| `--signer-key` | An owner's key file, repeatable, for an account with several owners. |
| `--issuer` | A public key file of an issuer to trust, repeatable; the `<key>.issuer.public.json` beside `--key` by default. |

Prints `bound`, `transaction`, `explorer` and `gas`.

#### mandate replace

Binds a new credential in place of an old one. The spend carries into the
new budget, and the old mandate is revoked in the same transaction. Issue
the new credential with `--mandate-key-file` naming the old one's key, in
the same directory, and the agent's commands find that key.

```bash theme={null}
metal-agent mandate replace --credential <file> --replaces <file> --key <file> --network testnet \
  --rpc-url <url> [--issuer <file>]...
```

`--replaces` names the credential being replaced; the other flags are
`bind`'s. Prints `replaced`, `bound`, `spent`, `transaction`, `explorer`
and `gas`.

#### mandate renew

Binds a new credential as a fresh mandate and revokes the one it replaces,
in one transaction. The new budget starts with nothing spent; a budget
never resets on its own.

```bash theme={null}
metal-agent mandate renew --credential <file> --replaces <file> --key <file> --network testnet \
  --rpc-url <url> [--issuer <file>]...
```

The flags are `replace`'s. Prints `revoked`, `bound`, `spent`,
`transaction`, `explorer` and `gas`.

#### mandate revoke

Revokes a mandate. Payments under it are refused from this transaction on.

```bash theme={null}
metal-agent mandate revoke --credential <file> --key <file> --network testnet --rpc-url <url> \
  [--signer-key <file>]...
```

Prints `revoked`, `transaction`, `explorer` and `gas`.

#### mandate status

Shows a mandate's terms and where it stands on the owner's account.

```bash theme={null}
metal-agent mandate status --credential <file> --network testnet --rpc-url <url>
```

Prints `mandate`, the terms as `credential create` prints them,
`account-type`, `bound`, and when bound `revoked`, `spent <amount> of <budget>` and `payments`. After a replace, `spent` and `payments` include
what the mandates it replaced spent and paid; `mandate verify` lists this
credential's payments only.

#### mandate pull

Pays an address the mandate allows, with no seller. The facilitator
submits it and pays the gas, unless `--key` names a key to submit it.

```bash theme={null}
metal-agent mandate pull --credential <file> --to <address> --amount <usdz> --network testnet \
  --rpc-url <url> [--payment-id <id>] [--key <file>] [--mandate-key-file <file>] [--record-refusal]
```

| Flag | Sets |
| - | - |
| `--to` | The address to pay. |
| `--amount` | The amount, in `*USDZ` to the cent. |
| `--payment-id` | Your id for the payment, such as a refund's or an invoice's. A retry passes the same id; another payment, another id. |
| `--key` | A key that holds `*USDZ` for gas, to submit the transaction itself instead of the facilitator. |
| `--mandate-key-file` | The mandate key file; by default the `.key.json` file in the credential's directory whose key the credential names. |
| `--record-refusal` | With `--key`, sends a payout the mandate refuses anyway, so the refusal is recorded on chain in a transaction that moves nothing. |

Checks the payout against the mandate first. One the mandate allows prints
`transaction`, then `outcome paid` with `spent <amount> of <budget>`,
`payer`, `payee`, `amount`, `explorer` and `gas`. One it refuses prints
`outcome refused, not sent` with `reason` and `recorded no`, and exits 1,
spending no gas; with `--record-refusal` it prints `outcome refused` with
the transaction that recorded it. One that passes the check and is refused
when its transaction runs prints `outcome refused` the same way. One the
receive policy contract holds in escrow prints `outcome held`: the payee was
not paid, and the amount counts against the budget; the payee, or the
authority its policy names, releases it. `paid` exits 0, a refusal 1,
`pending` 3 and `held` 4. A payout the facilitator refuses without sending a
transaction fails with the facilitator's reason; it is kept, and the same
command sends it again, which is refused again until what the reason names
changes. A run that sends a kept payout again and is refused, cannot reach
the facilitator, has a facilitator URL that is not http or https, or finds
the payout rejected by its check, fails saying
`the pull kept before may have been sent and can land until` a time: it can
still land until then.

The outcome is read from the chain. A sent payout with none yet prints
`outcome pending`, a `reason`, `can-land-until`, the time it can still land
until, and `kept`, the payment id it is kept under, or its amount and payee,
in `~/.metal-agent/pulls/<mandate>/`. Running the same command again sends
that same payout, which pays at most once, or reports how it ended; runs at
once send the same one. Once its outcome is reported, the same command makes
a new payment; under a `--payment-id`, a payout that was paid or held is
reported again, and nothing is sent, or fails, sending nothing, when the
chain does not hold it, as after a chain reset. The report starts `already
paid, nothing sent`, or `already held, nothing sent`, and its `spent` line
is the mandate's current spend. One the account refused paid nothing: the
same `--payment-id` may be sent with other values. An outcome that cannot be
recorded prints `kept …: the outcome was not recorded` after it, and the
same command reports it again. A kept payout that can no longer land is
followed by a new one, signed and checked in the same run, and a payout this
run sent that can no longer land prints `outcome refused, not paid` with its
`reason`.

Without `--payment-id`, a payout is known by its `--to` and `--amount`: a
second payout of the same amount to the same payee, while the first has no
reported outcome, sends the first again. Pass a `--payment-id` for each
payment that can repeat, such as refunds; a retry passes it, or leaves it
out, as the first run did. A payout is kept under this home directory and
this credential: a retry from another machine, or under a credential that
renewed or replaced it, signs a new payout. An event under the mandate that
the SDK does not decode fails the command with its topic and the account:
the payout may have paid, so do not pay it under another payment id.

#### mandate verify

Checks the mandate and every payment under it from the chain alone, or one
transaction. It reads the chain through an RPC endpoint and nothing else.

```bash theme={null}
metal-agent mandate verify --credential <file> --issuer <file>... --network testnet --rpc-url <url> \
  [--tx <hash> [--signed-offer <text>]]
```

| Flag | Sets |
| - | - |
| `--tx` | One transaction to check instead of all. |
| `--signed-offer` | The signed order `pay` printed for that transaction, checked against the payment. Needs `--tx`. |
| `--issuer` | The public key file of an issuer to trust, repeatable. Required. |

Prints `mandate`, four `step <n> pass|fail|skipped: <title>` lines each
with a detail line, one line per payment or refusal found, and
`verified yes|no`. With `--tx`, step 4's detail says whether a signed order
was checked, and names an order of another payment as such. The payments
listed are this credential's only: after a replace, verify each credential.
A failed check exits 1. An event under the mandate that
the SDK does not decode, as an account of another version emits, fails the
verification with its topic and the account.

## MCP

Serves `pay`, `fund` and `status` as MCP tools over stdio, and under a
mandate `mandate_pull`, `mandate_status` and `mandate_verify`. What `pay`
and `mandate_pull` spend is set when the server starts, by whoever starts
it: a key file and a per-payment limit, or one mandate's credential file,
which each call reads. The model calling the tools chooses no key, no
mandate and no higher limit. A server started with a mandate keeps that
credential file, so restart it with the new credential after
`mandate replace` or `mandate renew`. Under a mandate on testnet, set
`METAL_RPC_URL` in the server's environment, such as an `env` block in the
host's configuration.

```bash theme={null}
metal-agent mcp [--key <file>] [--max <usdz>]
metal-agent mcp --mandate <credential> [--mandate-key-file <file>]
```

| Flag | Sets |
| - | - |
| `--key` | The key file `pay` pays from; `~/.metal-agent/key.json` by default. |
| `--max` | The most one payment may cost; 1 `*USDZ` by default. |
| `--mandate` | The credential to pay under instead; takes neither `--key` nor `--max`. |
| `--mandate-key-file` | The mandate key file; by default the `.key.json` file in the credential's directory whose key the credential names. |

Every tool takes `network`, with no default; `fund` and `status` also
take `rpcUrl`. The mandate tools read the chain through the server's
`METAL_RPC_URL`, or devnet's default endpoint, take no `rpcUrl`, and fail
naming the endpoint's chain when it is not the network's. `mandate_pull`
submits pulls to the server's `METAL_FACILITATOR_URL`, or the network's
facilitator.

| Tool | Inputs |
| - | - |
| `pay` | `url`; `method`, `body` and `headers`. Under a key, `max` as well, which can only lower the server's limit. A refusal after signing, or a payment that may have settled, returns as an error ending with a `next:` line; under a mandate, the one for `mandate_revoked` says to restart the server with the credential that replaced it, and the one for a payment that may have settled says to look its nonce up with `mandate_verify`. |
| `fund` | `address`; on devnet, `amount` too. On testnet with the server's `METAL_RPC_URL`, an address that already holds about a full grant is reported funded, and the faucet is not asked. |
| `status` | `txHash`; on testnet, `rpcUrl` too, unless the server's environment sets `METAL_RPC_URL`. |
| `mandate_pull` | `to`, `amount` and `paymentId`, as `--payment-id`, required. Each outcome but `paid` ends with a `next:` line; `outcome refused`, and a pull the facilitator refuses or that is not sent, return as errors. `outcome pending` returns without `isError`, so a harness checks the `outcome` line, not `isError`. |
| `mandate_status` | Nothing more. An unbound or revoked mandate ends with a `next:` line. |
| `mandate_verify` | `issuers`, the issuer public key files to trust; `txHash` and `signedOffer`, as `--tx` and `--signed-offer`. `verified no` returns as an error. |

Each tool returns the lines its command prints, with the `next:` lines
above. Keys are created and imported through the CLI only, and no tool
sets or changes a mandate.

## What a mandate enforces

A mandate's limits are checked by the owner's account in the transaction
that moves the money, so no client, seller or facilitator can settle a
payment outside them.

| Limit | Set by | Refusal |
| - | - | - |
| The payees | `--payee`; any address when none is named | `mandate_payee_not_listed` |
| The most per payment | `--cap` | `mandate_cap_exceeded` |
| The most in total | `--budget`; a replacement carries the spend over | `mandate_budget_spent` |
| The number of payments | `--max-occurrences` | `mandate_occurrences_used` |
| The start | `--starts-in` | `mandate_outside_recurrence` |
| The expiry | `--expires-in` | `mandate_expired` |

A payment under a mandate can also be refused for these:

| Refusal | Meaning |
| - | - |
| `mandate_revoked` | The owner revoked or replaced the mandate. |
| `mandate_not_bound` | The account has no mandate bound from this credential. |
| `mandate_bad_signature` | The payment is not signed by the mandate key. |
| `mandate_outside_window` | The payment's validity window is not open. |
| `mandate_nonce_used` | This payment was already made or refused. |
| `transfer_would_fail` | The mandate allows it; the token refuses the transfer, such as for a short balance. |

> [card] [Pay under spending limits](https://docs.metalntwx.com/agents/spending-limits.md)
>
> The mandate commands in the order the owner and the agent run them.

> [card] [Facilitator](https://docs.metalntwx.com/agents/facilitator.md)
>
> Endpoints, limits, refusal reasons and retries.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.