---
name: madtaco-api
description: "ACTIVATE when integrating with or calling MadTaco verification and trust APIs — tax ID, IBAN, instrument lookup, email/phone validation, Chilean indicators, sanctions screening, company/domain checks, agent signup, billing, or MCP. Trigger on: madtaco, madtaco.dev, X-Api-Key, trust screen, validate tax-id, sanctions, /pricing.json, /llms.txt, MCP server setup."
license: MIT
metadata:
  author: madtaco
  icon: https://madtaco.dev/img/og/madtaco-icon.svg
---

# MadTaco API 🌮

> The checks agents run before they act.

Agent-native verification API. **Read live docs before spending credits.**

## Discovery (always first)

1. `GET https://{domain}/llms.txt` — endpoint catalog, auth, rate limits
2. `GET https://{domain}/pricing.json` — per-operation USD prices
3. `GET https://{domain}/skills/madtaco-api` — this skill (public URL for any agent)
4. `GET https://api.{domain}/v1/health` — uptime (no auth, no rate limit)

Production domain: `madtaco.dev`. Locally, read `config('brand.domain')` or env `BRAND_DOMAIN`.

## Choose integration path

| Situation | Use |
|-----------|-----|
| MCP-capable agent (Cursor, Claude Desktop) | MadTaco MCP server |
| Script, CI, direct HTTP, no MCP client | REST API |

### MCP setup

**Remote HTTP (preferred):**

```json
{
  "mcpServers": {
    "madtaco": {
      "url": "https://api.madtaco.dev/mcp",
      "headers": { "X-Api-Key": "your_key" }
    }
  }
}
```

**Local stdio:** `npx @madtaco/mcp` with `MADTACO_API_KEY` env var.

- Server card: `https://api.{domain}/.well-known/mcp/server-card.json`
- Setup guide: `https://{domain}/mcp`
- Registry: [Smithery](https://smithery.ai/servers/madtaco/madtaco-mcp)

Free MCP tools work without a key. Paid tools require `X-Api-Key` on the MCP request.

## Auth

- Header: `X-Api-Key: {token}` (or `Authorization: Bearer {token}`)
- Every response: `credits_charged` (0 for free ops)
- Authenticated responses: `balance_remaining`
- Paid POSTs: optional `Idempotency-Key` header (24h dedup; 409 on payload mismatch)

## Tiers & rate limits

| Tier | Limit | Paid checks |
|------|-------|-------------|
| Anonymous (no key) | 50/day per IP | No |
| Registered (verified account) | 100/day per key | No (402) |
| Funded (top-up ≥ $10) | 500/day included + $0.20/1000 overage | Yes |

Parse `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`. On 429, read `retry_after` and `hint` from the body.

**Failed or inconclusive checks are never charged.**

## Agent onboarding

```
POST /v1/accounts         {"email","name?"}
POST /v1/accounts/verify  {"account_id","code"}  → API key (tier 1)
POST /v1/billing/checkout {"amount":10} or {"pack":"200"|"1000"}  → checkout_url (tier 2)
POST /v1/billing/x402     {"amount":10}  → USDC top-up via x402 (tier 2, agent-native)
```

**x402 USDC payments (agents):** Fixed-price paid endpoints return HTTP 402 with `accepts[]` payment instructions when balance is too low. Pay with the `PAYMENT-SIGNATURE` header (x402 v2) and retry. Or top up credits first via `POST /v1/billing/x402` with the same header flow. Settlement is USDC on Base via Coinbase CDP facilitator. Requires `X402_RECIPIENT` wallet on the server.

Credentials are never returned via API. Humans get dashboard access via `POST /v1/accounts/invite-human`.

## REST quick reference

Base: `https://api.{domain}/v1`

**Free (no key required):**

- `POST /validate/tax-id` — `{"id","country"}`
- `POST /validate/iban` — `{"iban"}`
- `POST /validate/vat` — `{"vat"}` (EU format only; no live VIES)
- `POST /lookup/instrument` — `{"id_type","id_value","exchange_code?","mic_code?"}`
- `POST /validate/email` — `{"address","mode?":"syntax"|"full"}`
- `POST /validate/phone` — `{"number","mode?":"format"|"full"}`
- `GET /data/cl/{indicator}` — uf, utm, usd, eur, ipc
- `GET /data/cl/{indicator}/{date}` — historical YYYY-MM-DD

**Paid (tier 2 funded):**

- `POST /screen/sanctions` — `{"name","country?","match_threshold?"}`
- `POST /inspect/domain` — `{"domain"}`
- `POST /verify/company` — `{"country","name?","registration_number?"}` (GB only in v1)
- `POST /screen` — `{"entity":{...},"checks":["sanctions","registry","domain","email","phone"],"max_credits?"}`
- `GET /screens/{id}?wait=30` — poll or long-poll

**Platform (auth varies):**

- `GET /balance`, `GET /usage?period=7d|30d`
- `POST /webhook-secret/reveal`, `POST /webhook-secret/rotate` — HMAC secret for screen webhooks (funded tier)
- `POST /propose` — `{"capability","pledge_credits?"}`
- `GET /evidence/{id}` — signed evidence URL

Full catalog: `GET /skills/madtaco-api/endpoints` or [references/endpoints.md](references/endpoints.md) in-repo

## MCP tools

| Tool | Credits |
|------|---------|
| `validate_tax_id` | 0 |
| `validate_iban` | 0 |
| `validate_vat` | 0 |
| `lookup_instrument` | 0 |
| `validate_email` | 0 / 0.005 (`mode: full`) |
| `validate_phone` | 0 / 0.005 (`mode: full`) |
| `screen_sanctions` | 0.10 |
| `verify_company` | 0.15 |
| `inspect_domain` | 0.05 |
| `screen` | sum of completed checks |
| `create_account`, `verify_account`, `get_usage`, `propose_check` | 0 |
| `reveal_webhook_secret`, `rotate_webhook_secret` | 0 (funded tier) |

`screen` accepts `wait_seconds` for inline long-polling. Paid tools accept `idempotency_key`.

## Error handling

| Status | `error` | Action |
|--------|---------|--------|
| 429 | `rate_limited` | Wait `retry_after`; register or fund for higher limits |
| 402 | `insufficient_credits` or x402 `accepts[]` | Top up via `/billing/checkout` (card) or `/billing/x402` (USDC); or pay per-request with `PAYMENT-SIGNATURE` |
| 404 | `unknown_capability` | Use `POST /propose` or re-read `/llms.txt` |
| 409 | `idempotency_conflict` | New idempotency key or reuse exact payload |

## Composite screen workflow

1. Check balance and price via `GET /pricing.json`
2. `POST /screen` with entity fields and desired `checks`
3. If status is `queued`/`running`: `GET /screens/{id}?wait=30` or poll
4. Only `completed` checks appear in `checks_run` and are charged

## Implementation rules

- Fetch `/pricing.json` before paid operations — never hardcode prices
- Prefer free modes first (`syntax`, `format`) unless the user needs depth
- Use `Idempotency-Key` on paid POST retries
- Respect 429 — do not hammer; tier upgrade is the fix
- Read `credits_charged` from every response to track spend
- OpenAPI at `/openapi.yaml` may lag the live API — prefer `/llms.txt` as source of truth
