Mooj API v1 Quickstart API reference Postman

Mooj API

The payment layer for AI agents. Issue a real, capped virtual card and either use it yourself or hand the whole checkout to Mooj. Card controls, 3DS, and fraud caps are handled for you.

The Mooj API is organized around REST. It has predictable, resource-oriented URLs, accepts JSON request bodies, returns JSON responses, and uses standard HTTP verbs and status codes. Every response includes an X-Mooj-Request-Id header (also echoed as request_id in the body) so any call can be traced.

Base URLhttps://mooj-api-277196974190.us-central1.run.app
VersionAll endpoints are under /v1.
AuthBearer API key in the Authorization header.
Content typeapplication/json for all request bodies.
Amounts in requests are in US dollars (e.g. "amount": 20 means $20.00). Card and wallet math is exact to the cent internally.

Authentication #

Authenticate every request with your secret API key. Create and manage keys in the Mooj console under Developer → API keys. Keys look like mk_live_... and are shown only once at creation, so store yours securely.

Send the key as a bearer token. Keep it server-side and never commit it to source control; the examples below read it from an environment variable.

Shell
export MOOJ_API_KEY="mk_live_your_key_here"

# every request sends the bearer header:
curl https://mooj-api-277196974190.us-central1.run.app/v1/spend/example \
  -H "Authorization: Bearer $MOOJ_API_KEY"

A missing or invalid key returns 401 unauthorized. See Errors for the full list.


Quickstart #

Issue your first card in one call. The response comes back with a real, usable card capped at the amount you set.

cURL
curl https://mooj-api-277196974190.us-central1.run.app/v1/cards \
  -H "Authorization: Bearer $MOOJ_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"amount": 20, "merchant": "namecheap", "single_use": true}'
200 Response
{
  "id": "card_8f2a...",
  "brand": "visa",
  "last4": "8339",
  "exp_month": 4,
  "exp_year": 2033,
  "spend_limit": 20,
  "single_use": true,
  "status": "ACTIVE",
  "spend_request_id": "spr_1c9d..."
}

From here you can reveal the card to use it yourself, or skip cards entirely and let Mooj complete a checkout for you.


Guide: Give your agent a card #

The safest way to let an agent spend is a single-use card capped at exactly what the purchase should cost. It auto-freezes after the first charge, so it cannot be reused or over-spent.

  1. Issue a card with POST /v1/cards, setting single_use: true and amount to the cap.
  2. Reveal the number with GET /v1/cards/{id} only at the moment of use.
  3. Check the result with GET /v1/spend/{spend_request_id} (authorized / cleared / declined).

To teach your agent these calls in one paste, grab a ready tool file from Developer → Agent skills (Claude, OpenAI, and Gemini schemas). See Agent skills.

Guide: Complete a checkout #

Hand Mooj a plain-English task and a spend cap. Mooj mints a card, drives the merchant checkout in a real browser, auto-accepts 3DS, and pays. This is asynchronous: you get a checkout_id back, then poll it.

cURL
# 1. start the checkout (confirm_pay:false = dry run, stops at review)
curl https://mooj-api-277196974190.us-central1.run.app/v1/checkout \
  -H "Authorization: Bearer $MOOJ_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"task":"buy the domain mooj.click for 1 year","merchant":"namecheap","amount":20,"confirm_pay":false}'

# 2. poll until it finishes
curl https://mooj-api-277196974190.us-central1.run.app/v1/checkout/CHECKOUT_ID \
  -H "Authorization: Bearer $MOOJ_API_KEY"

Set confirm_pay: true to have Mooj pay autonomously, up to the cap. Poll status until it reaches a terminal state:

queued running awaiting_approval needs_login submitted blocked

If status is needs_login, the merchant requires a signed-in session. Set up a reusable login once with Connections, then pass its connection_id to the checkout.

Guide: Connect a merchant login #

Some merchants require an account. A connection is a reusable, isolated login your users complete once in a hosted browser session; every future checkout on that connection is already signed in.

  1. POST /v1/connections returns a connect_url. Open it so the user signs in on the merchant's own page (Mooj never sees the password).
  2. POST /v1/connections/{id}/complete persists the login. The connection becomes connected.
  3. Pass connection_id to POST /v1/checkout and the run executes signed-in as that user.

Guide: Handle events #

Instead of polling, get events pushed to your server the moment they happen. Register an endpoint in the Mooj console (Developer -> Webhooks); Mooj sends a signed POST for each event.

Events

card.authorized card.cleared card.declined checkout.submitted checkout.needs_login checkout.blocked

Each delivery is JSON: { "id", "type", "created", "data": { ... } }.

Verify the signature

Every request carries a Mooj-Signature: t=<unix>,v1=<hex> header. Recompute it with your endpoint's signing secret (shown once when you create the endpoint) and compare, so you know the event really came from Mooj.

Node — verify
import crypto from "node:crypto";

function verify(rawBody, header, secret) {
  const [t, v1] = header.split(",").map(p => p.split("=")[1]);
  const expected = crypto.createHmac("sha256", secret)
    .update(`${t}.${rawBody}`).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
}
Failed deliveries retry automatically. You can still poll GET /v1/spend/{id} and GET /v1/checkout/{id} at any time.

API reference

Every live endpoint, its parameters, and an example response. All requests require the Authorization: Bearer header from Authentication.

Cards #

Create a card

POST/v1/cards

Mint a virtual card capped at amount (USD) for a merchant.

FieldTypeReqDescription
amountnumberyesSpend cap in US dollars. Per-card ceiling is $5,000.
merchantstringyesMerchant the card is for, e.g. namecheap.
single_usebooleannoDefault true. Auto-freezes after the first charge.
networkstringnoauto (default), visa, or mastercard.
card_namestringnoLabel for the card in your dashboard.
200 Response
{
  "id": "card_8f2a...",
  "brand": "visa",
  "last4": "8339",
  "exp_month": 4,
  "exp_year": 2033,
  "spend_limit": 20,
  "single_use": true,
  "status": "ACTIVE",
  "spend_request_id": "spr_1c9d..."
}
Returns 402 insufficient_funds if the cap exceeds your available wallet balance.

Reveal a card

GET/v1/cards/{id}

Return the full card number, CVC, and expiry. Reveal only at the moment of use; Mooj never logs the PAN.

200 Response
{
  "id": "card_8f2a...",
  "last4": "8339",
  "number": "4775xxxxxxxx8339",
  "number_formatted": "4775 xxxx xxxx 8339",
  "cvc": "123",
  "exp": "04/33"
}

Close a card

POST/v1/cards/{id}/close

Close a card and release any unused reserve back to your wallet.

200 Response
{
  "id": "card_8f2a...",
  "status": "closed",
  "released_display": "$20.00",
  "available_to_issue_display": "$140.00"
}

Spend #

Get spend status

GET/v1/spend/{spend_request_id}

Check whether a card issued with POST /v1/cards was charged. Pass the spend_request_id from the create response.

not_started authorized cleared declined

200 Response
{
  "spend_request_id": "spr_1c9d...",
  "merchant": "namecheap",
  "decision": "APPROVED",
  "status": "cleared",
  "settled": true,
  "amount": 1.98
}

Checkout #

Start a checkout

POST/v1/checkout

Asynchronous. Mooj mints a card, drives the merchant checkout, handles 3DS, and (if authorized) pays. Returns a checkout_id to poll.

FieldTypeReqDescription
taskstringyesPlain-English description of what to buy.
merchantstringyesMerchant to buy from.
amountnumberyesMaximum USD to spend (becomes the card cap).
confirm_paybooleannoDefault false (dry run, stops at review). true pays up to the cap.
connection_idstringnoRun signed-in on a connection. Auto-matched by merchant if omitted.
card_holder_namestringnoName on the card for the run.
start_urlstringnoURL or bare domain to open first.
200 Response
{
  "checkout_id": "run_7a1e...",
  "status": "queued",
  "poll": "/v1/checkout/run_7a1e..."
}

Get checkout status

GET/v1/checkout/{checkout_id}
200 Response
{
  "checkout_id": "run_7a1e...",
  "status": "awaiting_approval",
  "task": "buy the domain mooj.click for 1 year",
  "merchant": "namecheap",
  "amount": 20,
  "card_last4": "4775",
  "review_total": 1.98,
  "order_id": null,
  "order_total": null,
  "needs_login": false,
  "error_reason": null
}

Connections #

Create a connection

POST/v1/connections
FieldTypeReqDescription
merchantstringyesMerchant to connect a login for.
user_refstringnoYour own reference for the end user this login belongs to.
200 Response
{
  "connection_id": "conn_5d2b...",
  "connect_url": "https://connect.browserbase.com/...",
  "status": "pending"
}

Complete a connection

POST/v1/connections/{id}/complete

Call after the user has signed in at the connect_url. Persists the login; status becomes connected.

List / get connections

GET/v1/connections
GET/v1/connections/{id}

List all connections, or poll a single connection's status (pending / connected).

Errors #

Mooj uses conventional HTTP status codes. The body carries a machine-readable string and a request_id.

StatusMeaning
200Success.
401unauthorized — missing or invalid API key.
402insufficient_funds — the requested cap exceeds available wallet balance.
404Resource not found, or not owned by your account.
400Bad request — a required field is missing or invalid.
Error body
{
  "error": "insufficient_funds",
  "request_id": "req_a1b2c3"
}

Postman collection #

Prefer to click instead of curl? Import the Mooj collection into Postman and every endpoint is ready to run.

Import URL
https://storage.googleapis.com/mooj-docs/mooj.postman_collection.json
  1. In Postman, choose Import and paste the URL above (or download and drop the file in).
  2. Open the collection's Variables and set apiKey to your mk_live_ key. baseUrl is already filled.
  3. Run Cards → Create a card to get your first card. The other requests reuse the same variables.
The collection sets Authorization: Bearer {{apiKey}} at the collection level, so every request inherits your key automatically.

Agent skills #

Teach your agent to use Mooj in one paste. The Mooj console (Developer → Agent skills) ships ready tool files for each stack:

Claude Code / AGENTS.md
A Markdown skill your agent loads directly.
Anthropic tool-use
JSON tool schema for the Claude API.
OpenAI function tools
JSON tool schema for the OpenAI API.
Google Gemini
Function declarations for the Gemini API.

Each file exposes the same four tools: issue_card, complete_purchase, get_checkout_status, and get_spend_status.

SDKs #

Official SDKs wrap this API so you do not have to hand-roll requests. Same surface in every language: cards, spend, checkout, connections.

Node
npm install @mooj/sdk · npmjs.com/package/@mooj/sdk
Python
pip install mooj · pypi.org/project/mooj
MCP server
npx -y @mooj/mcp · npmjs.com/package/@mooj/mcp
Node
import { Mooj } from "@mooj/sdk";
const mooj = new Mooj(process.env.MOOJ_API_KEY);
const card = await mooj.cards.create({ amount: 20, merchant: "namecheap", single_use: true });
Python
from mooj import Mooj
mooj = Mooj(api_key=os.environ["MOOJ_API_KEY"])
card = mooj.cards.create(amount=20, merchant="namecheap", single_use=True)
Agent (MCP)
{
  "mcpServers": {
    "mooj": {
      "command": "npx",
      "args": ["-y", "@mooj/mcp"],
      "env": { "MOOJ_API_KEY": "mk_live_your_key_here" }
    }
  }
}