# morscan API access for agents

Morscan is the block explorer and real-time API for the Morpheus AI network on
Base L2. This page tells an agent (or its operator) exactly how to get and use
an API key. There is no OAuth flow: authentication is a single API key minted
by a wallet signature.

## Getting a key

Registration is a wallet signature - nothing else. No email, no signup, no
payment. There are two ways in; both mint the same key (format
`mor_<32 chars>`).

### Headless (for agents - no browser needed)

The mint endpoints are plain HTTP. Three steps:

1. `GET https://morscan.io/console/wallet/challenge` returns
   `{ "nonce": "...", "message": "..." }`. The nonce is single-use and
   expires in 5 minutes.
2. Sign the returned `message` string with EIP-191 `personal_sign` using
   your EVM private key. The signature is the standard 65-byte `r||s||v` hex
   (v = 27 or 28).
3. `POST https://morscan.io/console/wallet/verify` with JSON
   `{ "wallet": "0x...", "signature": "0x...", "nonce": "..." }`. On first
   connect the response includes your `key` (`mor_...`) plus your `caps`
   and `stakeMor`. It also sets a session cookie; a returning wallet (key
   already minted) can read its existing key from
   `GET /console/wallet/status` using that cookie.

```bash
# 1. challenge
CHAL=$(curl -s https://morscan.io/console/wallet/challenge)
NONCE=$(echo "$CHAL" | jq -r .nonce)
MSG=$(echo "$CHAL" | jq -r .message)
# 2. sign $MSG with your wallet key (any EVM lib), e.g. in JS:
#      const sig = await wallet.signMessage(msg);   // ethers: EIP-191 personal_sign
# 3. verify -> key
curl -s -X POST https://morscan.io/console/wallet/verify \
  -H "Content-Type: application/json" \
  -d "{\"wallet\":\"$WALLET\",\"signature\":\"$SIG\",\"nonce\":\"$NONCE\"}"
# -> { "ok": true, "wallet": "0x...", "key": "mor_...", "caps": {...}, "stakeMor": 0 }
```

### Browser (for humans)

Open https://morscan.io/console with an EVM wallet (WalletConnect or an injected
wallet), connect, and sign the same one-time challenge. The console shows your
key immediately.

Rotate (`POST /console/key`) and delete (`POST /console/key/revoke`) are
done from /console while signed in. Deleting stops the key immediately; the
wallet session stays signed in, so a fresh key can be minted anytime with
`POST /console/key`. Once minted, the key itself is all an agent needs.

## Using the key

Send the key on every `/mor/v1/*` request. The canonical header:

```
X-Morscan-Key: mor_yourkeyhere
```

`Authorization: Bearer mor_yourkeyhere` is also accepted.

```bash
curl -s https://morscan.io/mor/v1/providers -H "X-Morscan-Key: mor_yourkeyhere"
```

## Free vs metered endpoints

Free, no key required:

- `GET /health` - sync status, block heights, service health
- `GET /mor/v1/price` - MOR/USD from the Base DEX (keyless calls are free;
  the same call WITH a key routes through metering and counts as 1)
- `GET /mor/v1/price/chart` - price history (same keyless/keyed rule)
- `GET /mor/v1/capacity` - your remaining quota (free even with a key)
- `GET /openapi.json`, `/llms.txt`, `/llms-full.txt`, `/chart.svg`, `/teaser`

Metered (key required, a flat 1 call each): everything else under `/mor/v1/`,
e.g. `/mor/v1/all`, `/mor/v1/providers`, `/mor/v1/bids`, `/mor/v1/sessions`,
`/mor/v1/models`, `/mor/v1/holders`, `/mor/v1/builder/*`, `/mor/v1/analytics`,
`/mor/v1/reputation`, `/mor/v1/provenance`. The full list with schemas is in
`https://morscan.io/openapi.json`.

## Pay per call (x402)

No key at all? Metered endpoints also accept **x402 micropayments**
(https://www.x402.org): **0.01 USDC per call** on Base, paid to a
self-custodied address, no account anywhere.

How it works:

1. Call a metered endpoint with no key. The response is **HTTP 402** with an
   x402 envelope: `accepts` advertises scheme `exact`, network `base`
   (eip155:8453), asset USDC
   (`0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913`), the `payTo` address,
   and `maxAmountRequired` in atomic units (10000 = 0.01 USDC at 6 decimals).
2. Sign an EIP-3009 `transferWithAuthorization` for exactly that transfer
   (any x402 client library does this) and retry with the `X-PAYMENT`
   header (base64 JSON: `{ x402Version: 1, scheme: "exact", network:
   "base", payload: { signature, authorization } }`).
3. The server verifies the payment cryptographically (payTo, amount, validity
   window, unused nonce, and the EIP-712 signature recovering the payer),
   serves the response, and acks with an `X-PAYMENT-RESPONSE` header.

Settlement is honest and explicit: **payment authorizations are verified
cryptographically at request time and settled on-chain in batches.** A signed
`transferWithAuthorization` stays valid within its window and can be
broadcast by anyone later, so deferred settlement loses nothing except time;
the ack's `transaction` field is empty until the batch lands. A failed or
replayed payment gets 402 again with an `error` field. An INVALID key still
gets a plain 401 (bad key is not the same as no key). Abuse guard: at most
100 unsettled authorizations per payer, plus the normal per-IP limits.

The free-key path above is usually the better deal for sustained use (60
req/min costs nothing); x402 exists so an agent holding only a funded wallet
can pay per call without registering anything.

## Rate limits

- Free connected-wallet key: **60 requests/min, 2,000/day, 40,000/month**.
- Staking MOR on the morscan builder subnet raises the SAME key's capacity:
  3 requests/min per MOR staked, and the volume caps rise with stake (the
  daily cap is always 5% of the monthly cap). Details: https://morscan.io/stake
- Daily caps reset at 00:00 UTC; monthly caps on the 1st (UTC). A separate
  per-IP limit (100/min) applies to keyless traffic.
- Paginated list endpoints (sessions, holders, builder events, provenance)
  return at most **100 rows per page**, server-enforced; a higher `limit` is
  clamped and the applied value is echoed in the response's pagination meta.
  Use `page` to paginate (max depth 1000).

On over-limit you get `429` with a `Retry-After` header (seconds) and a JSON
body with `reason` and `retry_after`. Successful keyed responses carry
`X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`, plus
`X-RateLimit-Limit-Day`/`-Remaining-Day` and `-Month` variants when volume
caps apply. Errors: `401` = missing/invalid key, `500` = retry with backoff
and check /health.

## Provenance verification

Every API response is Ed25519-signed: rows carry a `_receipt` id and the
receipt chain is queryable at `GET /mor/v1/provenance`. Public keys are
published at `https://morscan.io/.well-known/morscan-keys.json` (schema drm3-keys/v2)
so responses can be verified offline with the open-source
`@drm3labs-oss/provenance` package, or with the ~50-line runnable verifier
that ships in the repo (`npm run verify:receipt`, see
`scripts/verify-receipt.mjs` at https://github.com/DRM3Labs-OSS/morscan.io).
A step-by-step agent skill:
`https://morscan.io/.well-known/agent-skills/verify-provenance-receipt/SKILL.md`.

## More machine-readable surfaces

- `/.well-known/api-catalog` - RFC 9727 catalog of this API
- `/openapi.json` - OpenAPI 3.1 spec
- `/llms.txt` and `/llms-full.txt` - agent-oriented site guide
- `/.well-known/agent-skills/index.json` - task-level skill docs
- `/.well-known/mcp/server-card.json` - integration card (HTTP API; no MCP
  JSON-RPC transport is offered today)
- `GET /`, `/about`, `/contribute`, `/stake` with `Accept: text/markdown`
  return markdown versions of those pages
