Source URL: https://mag3nt.com/skill.md
Title: mag3nt API - Agent Skills Guide

---
name: mag3nt
version: 0.6.0
description: Issue pre-funded payment credentials for autonomous AI agents. One card pays across x402, AP2, and MPP, settling in USDC on Base, Ethereum, Polygon, Arbitrum, Solana, and Tempo.
homepage: https://mag3nt.com
user-invocable: true
metadata: {"category":"finance","primaryEnv":"MAG3NT_API_KEY","requires":{"env":["MAG3NT_API_KEY"]}}
---

```
MAG3NT API QUICK REFERENCE v0.6.0
Base:   https://api.mag3nt.com
Auth:   Authorization: Bearer <MAG3NT_API_KEY>   (key prefix: mag3nt_live_)
Get a key: https://mag3nt.com -> Developer -> Generate API Key
Thin client (no SDK): npx mag3nt <command>   # package: mag3nt → api.mag3nt.com
App / checkout: https://mag3nt.com
Docs:   This file is canonical. Full reference: https://docs.mag3nt.com
MCP:    https://mcp.mag3nt.com

What mag3nt does: issues pre-funded credentials ("cards") that let an agent pay
any x402, AP2, or MPP endpoint. One card, multiple protocols. Settlement is in
USDC on Base / Ethereum / Polygon / Arbitrum / Solana / Tempo.

Issue & manage cards:
  POST /api/issue/bulk          -> issue many pre-funded cards in one request (Idempotency-Key required)
  POST /api/issue               -> issue a single pre-funded card
  GET  /api/cards               -> list your cards
  GET  /api/cards/:id/transactions -> a card's transaction history
  GET  /api/transactions        -> account activity across all cards (incl. closed)
  POST /api/cards/:id/freeze    -> freeze a card
  POST /api/cards/:id/unfreeze  -> unfreeze a card
  POST /api/cards/:id/claim     -> move unspent funds back to treasury (full or partial)
  POST /api/cards/:id/close     -> retire an empty card with no open obligations

Pay with a card (outbound):
  POST /api/pay                 -> pay any x402 / AP2 / MPP endpoint; auto-detects protocol and settles on-chain

Get paid (inbound, pay links):
  POST /api/paylinks            -> create a shareable / agent-ready payment link
  GET  /api/pay/:code/prepare   -> discover payment requirements for a link (public, no auth)
  POST /api/pay/:code/settle    -> submit on-chain proof to settle a link (public)

AP2 (Agent Payments Protocol):
  GET  /api/ap2/instruments     -> list a card's payment instruments
  POST /api/ap2/mandate         -> issue a Payment Mandate (SD-JWT)
  POST /api/ap2/receipt         -> process a Payment Receipt
  GET  /api/ap2/.well-known/jwks.json -> public verification keys

Developer keys & webhooks:
  POST /api/keys/validate       -> verify the current API key
  POST /api/webhooks            -> register a signed webhook (HMAC-SHA256); receives all event types

Rules: requests are JSON. Authenticate every call with Bearer <MAG3NT_API_KEY>.
Errors: HTTP status + JSON { "error": "message" }.
```

# mag3nt API - Agent Skills Guide

This skill documents the public mag3nt REST API. Prefer `npx mag3nt` (no SDK install) or plain HTTP against `https://api.mag3nt.com`. Dashboard and checkout live on `https://mag3nt.com`.

## What you can do with mag3nt

1. **Issue pre-funded cards** for agents, individually or in bulk. Each card is scoped to a spend limit, optional expiry, optional merchant-category (MCC) restrictions, and can be single-use.
2. **Pay any agentic-commerce endpoint** with one card. `POST /api/pay` auto-detects whether the target speaks x402, AP2, or MPP, prices the request, and settles in USDC on-chain.
3. **Get paid** by creating pay links that agents and humans can settle on-chain, then reconcile automatically.
4. **Receive `payment.settled` webhooks** so a seller backend can release goods or services the moment a payment confirms, without mag3nt holding the seller's upstream API key.

The core idea: a mag3nt card is a protocol-agnostic spending credential. You fund it once, then an agent uses it across x402, AP2, and MPP without you re-wiring anything per protocol.

## Base URL & Auth

- Base URL: `https://api.mag3nt.com`
- Auth header: `Authorization: Bearer <MAG3NT_API_KEY>`
- Content-Type: `application/json`

API keys carry the `mag3nt_live_` prefix and are created from the dashboard:
open `https://mag3nt.com`, go to the **Developer** tab, and choose **Generate API Key**. The full key is shown once at creation, so store it securely.

Quick env setup:

```bash
export MAG3NT_API_URL="https://api.mag3nt.com"
export MAG3NT_API_KEY="mag3nt_live_..."   # from the Developer tab
```

Validate the key before you rely on it:

```bash
curl -sS -X POST "$MAG3NT_API_URL/api/keys/validate" \
  -H "Authorization: Bearer $MAG3NT_API_KEY" \
  -H "Content-Type: application/json"
```

Returns `{ "valid": true, "wallet_address": "0x...", "authenticated_at": "..." }`.

## Identifiers

- Card IDs use the `mag3nt_` prefix (legacy cards may use `sx_`; both remain valid).
- Card tokens use the `tok_` prefix. The token is the bearer secret an agent presents when spending a card. Treat it like a password.
- Supported networks (CAIP-2): `eip155:8453` (Base), `eip155:1` (Ethereum), `eip155:137` (Polygon), `eip155:42161` (Arbitrum), `eip155:4217` (Tempo), `solana:mainnet`. Settlement asset is USDC.

## Core flow 1: Issue pre-funded cards

### Bulk issue (recommended for fleets)

`POST /api/issue/bulk` issues many cards in one atomic request. An `Idempotency-Key`
header is required so a retry never double-issues.

```bash
curl -sS -X POST "$MAG3NT_API_URL/api/issue/bulk" \
  -H "Authorization: Bearer $MAG3NT_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "network": "eip155:8453",
    "asset": "USDC",
    "cards": [
      { "purpose": "Research Agent", "amount": 25 },
      { "purpose": "Trading Bot",    "amount": 50 }
    ]
  }'
```

- `network` (optional, defaults to `eip155:8453`), `asset` (optional, defaults to `USDC`).
- `cards`: array of `{ "purpose": string, "amount": number }`. Maximum 500 per request. Each `amount` must be greater than 0.
- Returns the created cards, each with its `id` (`mag3nt_...`) and `token` (`tok_...`).

### Single issue

`POST /api/issue` issues one card and accepts finer-grained controls.

```bash
curl -sS -X POST "$MAG3NT_API_URL/api/issue" \
  -H "Authorization: Bearer $MAG3NT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "purpose": "Data subscription",
    "amount": 20,
    "network": "eip155:8453",
    "asset": "USDC",
    "expires_in": 720,
    "single_use": false
  }'
```

- `purpose` and `amount` are required.
- `expires_in`: lifetime in hours (omit or `0` for no expiry).
- `mcc_locks`: optional comma-separated merchant category codes to restrict spend.
- `single_use`: optional boolean for one-shot credentials.

## Core flow 2: Pay any endpoint with a card

`POST /api/pay` is the universal outbound payment call. Give it a card and a target
URL. mag3nt fetches the URL, reads the 402 / mandate / MPP challenge, prices it
against the card limit, settles in USDC on-chain, and returns the resource.

```bash
curl -sS -X POST "$MAG3NT_API_URL/api/pay" \
  -H "Content-Type: application/json" \
  -d '{
    "card_id": "mag3nt_...",
    "card_token": "tok_...",
    "url": "https://api.example.com/x402/resource"
  }'
```

- `card_id` and `card_token` are required.
- `url` is the protected endpoint to pay and fetch. The same call works whether the endpoint speaks x402, AP2, or MPP.
- Optional: `method`, `headers`, `body` to forward to the target endpoint.

The card token authorizes the spend, so this endpoint does not need the API key. Only share `card_token` with the agent that is meant to spend that specific card.

## Core flow 3: Get paid with pay links

Create a link an agent or a human can pay. The link is agent-ready: it advertises
its payment requirements over a public `prepare` endpoint, then accepts on-chain
settlement proof.

```bash
# 1. Create a pay link bound to one of your cards
curl -sS -X POST "$MAG3NT_API_URL/api/paylinks" \
  -H "Authorization: Bearer $MAG3NT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "card_id": "mag3nt_...",
    "amount": 5,
    "memo": "API access",
    "accepted_protocols": ["x402", "ap2", "mpp"]
  }'

# 2. A payer discovers requirements (public, no auth)
curl -sS "$MAG3NT_API_URL/api/pay/<code>/prepare"

# 3. The payer sends USDC on-chain, then submits proof (public)
curl -sS -X POST "$MAG3NT_API_URL/api/pay/<code>/settle" \
  -H "Content-Type: application/json" \
  -d '{
    "protocol": "x402",
    "tx_hash": "0x...",
    "from_address": "0x...",
    "amount": 5
  }'
```

- `card_id` is the only required field when creating a link. Optional: `amount` (omit for "any amount"), `memo`, `type`, `max_uses`, `expires_in`, `network`, `asset`, `accepted_protocols`.
- Settlement is verified on-chain and replay-protected (a `tx_hash` settles at most once).

## Core flow 4: webhooks (for sellers)

Register a webhook to be notified the instant something happens on your
credentials, so your backend can release goods, reconcile, or react to a
lifecycle change. mag3nt signs every delivery with HMAC-SHA256 using a
per-endpoint secret (prefix `whsec_`) shown once at creation.

Every endpoint receives ALL event types. Switch on the envelope `type` field
(mirrored in the `X-Mag3nt-Event` header) to handle only what you need:

| `type` | When it fires | `data` highlights |
|---|---|---|
| `payment.settled` | A payment settled (pay link, x402/AP2/MPP receive, stream tick) | `settlement_id`, `amount`, `net_amount`, `asset`, `tx_hash`, `receiver_card_id`, `settlement_mode` |
| `payment.refunded` | A card-funded outbound payment failed and the card was re-credited | `transaction_id`, `card_id`, `amount`, `reason` |
| `credential.ready` | A managed holder finished provisioning on-chain (async heal) | `card_id`, `status`, `holder_address`, `actor: "system"` |
| `credential.frozen` | A credential was frozen (transfers blocked) | `card_id`, `status`, `actor` |
| `credential.unfrozen` | A frozen credential returned to active | `card_id`, `status`, `actor` |
| `credential.closed` | A credential was permanently retired | `card_id`, `status`, `actor` |
| `credential.seized` | Operator/compliance seized funds from the holder | `card_id`, `amount`, `tx_hash`, `actor: "operator"` |
| `credential.funds_claimed` | Unspent balance was swept back to treasury | `card_id`, `amount`, `asset`, `actor` |
| `crt.deployed` | A credential token finished deploying on-chain (async) | `card_id`, `symbol`, `token_address`, `deploy_tx` |
| `crt.deploy_failed` | A credential token deploy attempt failed; the cron will retry | `card_id`, `symbol`, `error` |
| `subscription.charged` | A recurring billing agreement charged successfully | `agreement_id`, `charge_id`, `amount`, `period` |
| `subscription.charge_failed` | A recurring charge failed; dunning will retry | `agreement_id`, `error`, `failures`, `retry_at` |
| `subscription.canceled` | Agreement canceled, expired, or envelope exhausted | `agreement_id`, `reason` |

The envelope is always `{ id, type, created, data }`. The same `id` is delivered
to every subscribed endpoint and is stable across retries — use it as your
idempotency key. Reversals are NOT chargebacks: on-chain settlement is final, so
there is no `dispute.*` event.

```bash
curl -sS -X POST "$MAG3NT_API_URL/api/webhooks" \
  -H "Authorization: Bearer $MAG3NT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://your-backend.example.com/mag3nt/webhook" }'
```

Verify each delivery before trusting it. Header format:
`X-Mag3nt-Signature: t=<unix>,v1=<hmac>`. Compute HMAC-SHA256 over
`` `${t}.${rawBody}` `` with your per-endpoint `whsec_` secret and compare `v1`
in constant time. Reject timestamps outside ~5 minutes.

```js
import { createHmac, timingSafeEqual } from "node:crypto";

function verifyMag3nt(rawBody, signatureHeader, whsec) {
  const parts = Object.fromEntries(
    signatureHeader.split(",").map((kv) => {
      const i = kv.indexOf("=");
      return [kv.slice(0, i).trim(), kv.slice(i + 1).trim()];
    }),
  );
  const expected = createHmac("sha256", whsec)
    .update(`${parts.t}.${rawBody}`)
    .digest("hex");
  const a = Buffer.from(expected);
  const b = Buffer.from(parts.v1 || "");
  return a.length === b.length && timingSafeEqual(a, b);
}
```

On a valid event, act on it (e.g. `payment.settled` → unlock/fulfill), then return 2xx quickly.
Failed deliveries are retried automatically for up to an hour.

## Core flow 5: recurring billing (subscriptions)

Charge a payer on a schedule without holding their keys. Consent is an AP2
open mandate carrying a `payment.recurring` constraint; mag3nt's billing engine
handles the schedule, retries (dunning), and the lifetime spend envelope.

```bash
# 1. Payer issues a recurring open mandate scoped to your pay link
curl -sS -X POST "$MAG3NT_API_URL/api/ap2/mandate" \
  -H "Authorization: Bearer $PAYER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "card_id": "card_...",
    "type": "open",
    "max_amount": 120,
    "allowed_payees": ["paylink:PL_ABC123"],
    "recurring": { "amount_per_period": 10, "period_days": 30 }
  }'

# 2. Create the agreement from that mandate (first charge runs inline)
curl -sS -X POST "$MAG3NT_API_URL/api/billing/agreements" \
  -H "Authorization: Bearer $PAYER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "open_mandate": "<mandate JWT>", "pay_link_code": "PL_ABC123" }'
```

- Provide exactly one of `pay_link_code` (pay a merchant's link each period) or `plan_ref` (internal plans, e.g. `membership:month`).
- The per-charge `amount` defaults to the mandate's `amount_per_period` and can never exceed it; total charges can never exceed the mandate `max_amount` envelope.
- Failed charges retry with backoff (1h, 6h, 24h, 48h); after 4 consecutive failures the agreement auto-cancels and `subscription.canceled` fires with `reason: "payment_failed"`.
- Cancel anytime with `POST /api/billing/agreements/{id}/cancel` (body `{ "at_period_end": true }` to let the current period run out). Merchants and payers can both cancel.
- Watch `subscription.charged` / `subscription.charge_failed` / `subscription.canceled` webhooks to react.

## API Endpoints Reference

| Endpoint | Method | Path | Notes |
|----------|--------|------|-------|
| Bulk issue cards | POST | `/api/issue/bulk` | Body: `network`, `asset`, `cards[]` of `{purpose, amount}`. Header: `Idempotency-Key` |
| Issue single card | POST | `/api/issue` | Body: `purpose`, `amount`; optional `network`, `asset`, `expires_in`, `mcc_locks`, `single_use` |
| List cards | GET | `/api/cards` | Returns `{ cards: [...] }` |
| Card transactions | GET | `/api/cards/{id}/transactions` | Per-card spend history |
| Account activity | GET | `/api/transactions` | Activity across all cards, including closed. Each row tagged with `card_purpose` and `card_status` |
| Freeze card | POST | `/api/cards/{id}/freeze` | Suspends spending |
| Unfreeze card | POST | `/api/cards/{id}/unfreeze` | Resumes spending |
| Move funds to treasury | POST | `/api/cards/{id}/claim` | Sweeps unspent funds back to your treasury balance. Body optional `amount` for a partial claim on ACTIVE/FROZEN cards; omit to sweep all. EXPIRED cards always fully sweep |
| Close card | POST | `/api/cards/{id}/close` | Retires an empty card (zero balance, no pending tx, no open streams, no active mandates). Closed cards leave the wallet view; history stays in account activity |
| Pay any endpoint | POST | `/api/pay` | Body: `card_id`, `card_token`, `url`; optional `method`, `headers`, `body` |
| Create pay link | POST | `/api/paylinks` | Body: `card_id`; optional `amount`, `memo`, `type`, `max_uses`, `expires_in`, `network`, `asset`, `accepted_protocols` |
| Prepare pay link | GET | `/api/pay/{code}/prepare` | Public. Returns payment requirements + accepted protocols |
| Settle pay link | POST | `/api/pay/{code}/settle` | Public. Body: `protocol`, `tx_hash`, `from_address`, `amount` |
| List AP2 instruments | GET | `/api/ap2/instruments` | Query: `card_id`, `card_token` |
| Issue AP2 mandate | POST | `/api/ap2/mandate` | Body: `card_id`, `type`, `total` (session) or agent-mode fields |
| Process AP2 receipt | POST | `/api/ap2/receipt` | Settle against a mandate |
| AP2 public keys | GET | `/api/ap2/.well-known/jwks.json` | JWKS for verifying mandates |
| Validate API key | POST | `/api/keys/validate` | Returns `{ valid, wallet_address }` |
| Register webhook | POST | `/api/webhooks` | Body: `url`. Returns a `whsec_` secret once |
| Create billing agreement | POST | `/api/billing/agreements` | Body: `open_mandate` + exactly one of `pay_link_code` / `plan_ref`; optional `amount`, `description`, `defer_first_charge` |
| List billing agreements | GET | `/api/billing/agreements` | Query: `role=payer` (default) or `role=merchant` |
| Agreement detail + charges | GET | `/api/billing/agreements/{id}` | Payer or merchant only |
| Cancel agreement | POST | `/api/billing/agreements/{id}/cancel` | Body optional `{ "at_period_end": true }` |

## Fees & plans

Outbound settlement fee is 0.5% + $0.001 USDC per transaction (payer-side; the
merchant always receives 100%). Network withdrawal fees are flat per chain and
configurable. There are no per-transaction overrides.

Native Token Rails (DIRECT project-token accept) is tiered by settled DIRECT
payments per calendar month:

| Tier | Price | Included DIRECT settles / month |
|---|---|---|
| Free | $0 | 100 |
| Starter | $49/mo ($490/yr) | 2,500 |
| Growth | $199/mo ($1,990/yr) | 25,000 |
| Enterprise | Custom — contact Mag3nt | Unlimited |

Inbound DIRECT payments are never blocked by plan limits. Past your monthly
quota each settle debits a small $MAG3NT overage fee from your prepaid fee
balance (debt is tolerated up to a floor; past it, pay-link discovery is
withheld until you top up or upgrade). Check `GET /api/membership` for your
tier, current usage, and remaining quota. Upgrade with
`POST /api/membership/checkout` (body: `tier`, `interval`, `asset`) or
subscribe via a recurring billing agreement with `plan_ref` like
`membership:growth:month`.

## Error Responses

Errors return JSON with an HTTP status:

```json
{ "error": "message" }
```

| Status | Meaning | Common cause |
|--------|---------|--------------|
| 400 | Bad Request | Missing or invalid fields |
| 401 | Unauthorized | Missing or invalid API key |
| 403 | Forbidden | Insufficient balance, frozen card, or permission denied |
| 404 | Not Found | Resource does not exist |
| 409 | Conflict | Duplicate action |
| 429 | Rate Limited | Too many requests, back off and retry |
| 500 | Server Error | Transient, retry later |

## Security

- Never share your API key or a card token in logs, posts, or screenshots.
- A card token (`tok_`) authorizes spending on that card. Scope each agent to its own card.
- Rotate a key from the Developer tab if you suspect exposure.
- Verify webhook signatures before acting on a delivery.

---

Built for agents.
