Dino's flagship developer flow is governed spend for agents: fund a wallet, attach a spending key to the right policy profile (the default profile, card, and key are auto-provisioned for new teams), then call the public REST /v1 API.
For a ready-made shell script and localhost tool harness, see Agent integration starter.
For a no-real-money setup, start with Sandbox. It covers din_test_ keys, DINO_SANDBOX_MODE, and the USD faucet.
For interactive API docs (all /v1 routes and schemas), open api.dino.id (Scalar).
If an LLM or assistant is part of your product, do not pass the spend key through model context. Put a constrained tool or server boundary in front of Dino instead. See Connecting AI Agents to Dino.
#Current status
Today, the canonical shipped surface for agent spend is:
REST /v1- Dino spending keys
- dashboard approvals and ledger
- webhook-first reconciliation
CLI, MCP spend tools, and the in-repo TypeScript SDK are convenience layers over this same REST contract.
#TypeScript SDK (not on npm yet)
@dino/agent-spend-sdk ships inside the dino-banking monorepo for examples and internal apps. It is not published to npm yet — npm install @dino/agent-spend-sdk will 404 until we publish.
Until then, external integrations should:
- call REST directly (
curlor your HTTP client), or - clone the repo and run the runnable examples under
examples/.
For a guided terminal walkthrough (virtual card checkout intent + governed spend, dashboard approvals, optional browser opens), use the dinobank agent demo command in the open-source dino-banking repo — see Interactive CLI demo below.
#What you need
Before making your first request:
- In the Dino dashboard, add a funding source and fund your team wallet.
- Default path: new teams already have a default policy profile, proxy card, and API key from provisioning — copy the key from Agent Bank → API Keys or open Cards → View policy for the full panel (budget, keys, ledger).
- Extra profiles: create another budget only if you need separate caps or rules (Agent Bank → Budgets). Tune rules from Cards → View policy on a card for that profile (or Budgets → View — same destination).
- Proxy cards: see Proxy cards: issue, manage, test for how simulated vs live (Stripe/Lithic) issuance differs, wallet reserves on live single-use cards, and a short testing checklist.
- Issue additional Dino spending keys from View policy → Keys when you need more than one credential per profile.
The plaintext spending key is only shown once.
#Runnable example
The monorepo includes a copyable example for this flow:
git clone https://github.com/dino-id/dino-banking.git
cd dino-banking/examples/agent-spend-quickstart
cp .env.example .env
bun run start
See examples/agent-spend-quickstart.
#Interactive CLI demo
The dino-banking monorepo ships dinobank, a developer CLI that includes agent demo: an interactive menu (virtual card flow with checkout intents + JIT proxy credential, and a machine-spend flow with an HTTP 402 probe plus POST /v1/spend-requests). When a decision needs a human, the demo prints an approval link to app.dino.id (or your DINO_DASHBOARD_URL) and can open it in your browser, then polls the API until you approve or decline — same contract as production (approval_url on spend responses).
Prerequisites: Bun, a local clone of the repo, and a Dino spending key (din_…).
git clone https://github.com/dino-id/dino-banking.git
cd dino-banking
bun install
export DINO_SPEND_KEY="din_…"
bun run dinobank -- agent demo
Production defaults (when unset): API https://api.dino.id, dashboard https://app.dino.id. For local stacks, set DINO_API_URL and DINO_DASHBOARD_URL so the CLI and the approval tabs hit the same environment.
Useful options:
--key din_…— spending key instead ofDINO_SPEND_KEY.--no-browserorDINO_DEMO_NO_BROWSER=1— print approval and merchant URLs only; do not call the OS “open” helper.
The demo requires an interactive terminal (TTY). More detail: packages/dino-bank-cli/README.md in the same repo.
#Request spend
Use the public agent-spend API:
curl -sS -X POST "https://api.dino.id/v1/spend-requests" \
-H "Authorization: Bearer YOUR_DINO_SPEND_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"amount_cents": 12000,
"currency": "usd",
"merchant_name": "AWS",
"reason": "GPU runtime for evaluation job"
}'
#Canonical agent loop
Use this exact loop in agents and platform integrations:
POST /v1/spend-requestswith an idempotency key.- If
status=needs_approval, send operator toapproval_urland wait for webhook. - Reconcile final state from webhook payload (or
GET /v1/spend-requests/:idfallback polling).
#Possible responses
#Approved
{
"id": "req_123",
"status": "approved",
"decision_reason": "Spend request approved",
"budget_period": "monthly",
"remaining_budget_cents": 38000,
"remaining_monthly_budget_cents": 38000,
"amount_cents": 12000,
"currency": "usd",
"merchant_name": "AWS"
}
#Needs approval
{
"id": "req_124",
"status": "needs_approval",
"decision_reason": "Amount requires approval",
"budget_period": "monthly",
"remaining_budget_cents": 50000,
"remaining_monthly_budget_cents": 50000,
"amount_cents": 60000,
"currency": "usd",
"merchant_name": "OpenAI",
"approval_url": "https://app.dino.id/agents/approvals?spendRequestId=req_124"
}
#Declined
{
"id": "req_125",
"status": "declined",
"decision_reason": "Amount would exceed the budget for this period",
"budget_period": "monthly",
"remaining_budget_cents": 5000,
"remaining_monthly_budget_cents": 5000,
"amount_cents": 12000,
"currency": "usd",
"merchant_name": "Vercel"
}
#Check status
curl -sS "https://api.dino.id/v1/spend-requests/req_123" \
-H "Authorization: Bearer YOUR_DINO_SPEND_KEY"
#Status model (shared across API, CLI, and dashboard)
- Decision-time statuses:
approved,declined,needs_approval - Later lifecycle statuses (via execution / reconciliation):
completed,cancelled,failed,expired - Treat
needs_approvalas pending, not failure
#Check remaining budget
curl -sS "https://api.dino.id/v1/balance" \
-H "Authorization: Bearer YOUR_DINO_SPEND_KEY"
#Error handling
Expect machine-readable errors in this shape:
{
"error": {
"code": "rate_limited",
"message": "Rate limit exceeded"
}
}
Common codes:
invalid_api_keyrevoked_api_keyinvalid_requestfunding_source_budget_exceededplan_spend_volume_exceededrate_limited
Retry rules:
- Retry
429and500with backoff. - Reuse the same
Idempotency-Keywhen retryingPOST /v1/spend-requests. - Do not blindly retry
401,403,404, or402.
#Approvals and ledger
If a request returns needs_approval, route the operator to approval_url and treat the request as pending. Every decision is persisted to Dino's ledger for later audit.
Once an operator acts, your integration needs to learn the outcome. Two options:
Option A — Webhooks (recommended once configured)
Register an HTTPS endpoint in the Dino dashboard under Developer → Webhooks. Dino posts a signed spend_request.approved or spend_request.declined event when the decision is made. See Agent Spend Webhooks for registration, signature verification, and retry details.
Option B — Polling (fallback)
Call GET /v1/spend-requests/:id every 30–60 seconds until the status reaches a terminal value (approved, declined, cancelled, failed, expired):
curl -sS "https://api.dino.id/v1/spend-requests/req_124" \
-H "Authorization: Bearer YOUR_DINO_SPEND_KEY"
Use polling when you do not yet have a registered webhook endpoint, or as a recovery path when a webhook delivery was missed.
#Next steps
- Interactive CLI demo —
dinobank agent demoin dino-banking - Agent integration starter
- Agent Spend Webhooks
- Connecting AI Agents to Dino
- API Reference
- Cross-Team Transfers — REST
/v1/transfersbetween workspaces - Agent Spend Errors
- Agent Spend Changelog
- Assistant and MCP Integration