Write endpoints that involve money — like initiating payments — always require your confirmation in the Moneda app before anything happens.
Base URL
/v1. Include your Bearer token in the Authorization header:
Response shape: ?view=full vs ?view=lite
Every GET /v1/* endpoint accepts an optional view query parameter that selects the response shape. This lets LLM agents and terminals consume a compact version of each response without dropping existing integrations.
lite is a strict subset of fields with two renames:
balances[].accountName→balances[].type(on/v1/balances, for semantic clarity)points_activity[].createdAt→points_activity[].date
null, and "" are also dropped from the response body on every lite call — 0, false, and "0" are preserved (balance of zero is a real answer). This is a minor shape change on lite only; the full shape is unchanged.
Example:
/v1/health, /v1/exchange-rates, /v1/points/balance, /v1/settings, knowledge search) ignore view because there’s nothing to trim.
Health
GET /v1/health
Server health check. No authentication required. ResponseBalances & Finances
GET /v1/balances
Returns your account balances. Scope:read:balances
Query parameters
Response (full)
?view=lite)
Drops source, snapshotTimestamp, and notice. On the snapshot-fallback path only, collapses all 4 metadata fields to one optional stale field. Renames accountName → type per row.
GET /v1/lifetime-savings
Returns your lifetime accumulated savings from using Moneda — the total fees Moneda covered on your behalf (sponsored network and transfer fees) plus the discount your plan gives you versus the Standard plan, in your display currency. Scope:read:balances
Response
GET /v1/transactions
Returns your transaction history with powerful filtering. Scope:read:transactions
Query parameters
Response (full)
signer names the passkey that approved the payment: label is the nickname
(falling back to the provider name) and kind is primary or backup. It is
absent on rows that no user signed — anything created before signer
provenance was recorded, and every server-initiated movement such as an
incoming deposit, a scheduled transfer, an on-ramp, or a card settlement.
Absent means “no user signature on file”, not “an unrecognised key”.
Response (
?view=lite)
Drops typeGroup, type, category, note, reference, exchanged*, received*, and counterparty raw address/iban/account/routing (already masked, still unused by LLM agents). Keeps hash, direction, amount, currency, status, date, and the trimmed counterparty. Per row ≈40–50 % smaller.
GET /v1/transactions/{hash}
Single-resource lookup by transaction hash. Scope:read:transactions
Path parameters
Query parameters
Returns a single transaction (same shape as the list items above). 404 if not found or not owned by this user.
GET /v1/spending/by-type-group
Spending grouped by transaction type group (formerly/v1/spending/summary). Scope: read:spending
Query parameters
Response
GET /v1/spending/by-category
Spending grouped by user-assigned category (Groceries, Restaurants, Transport, etc.). Transactions without a category land in anUNCATEGORIZED bucket. Scope: read:spending
Query parameters
GET /v1/spending/by-contact
Total amount sent to a single recipient (Moneda user, external bank, or external wallet) over a window. Scope:read:spending
Query parameters
GET /v1/spending/by-merchant
Spending grouped by recipient. Each Moneda user gets their own bucket; off-ramps share one bucket per type (bank-withdrawal, external-wallet, coinbase, wallet-connect). Scope: read:spending
Query parameters
GET /v1/spending/comparison
Compare spending totals across two arbitrary windows (e.g. this month vs. last month) with absolute and percentage delta. Scope:read:spending
Query parameters
GET /v1/spending/daily
Daily spending totals for a stablecoin over a rolling window or absolute UTC range. Scope:read:spending
Query parameters
GET /v1/spending/transactions
List the underlying transactions for a spending window (or a category/merchant bucket). Used to drill into a spending breakdown. Scope:read:spending
Query parameters
GET /v1/exchange-rates
Current USD/EUR exchange rate. Scope:read:rates
Query parameters
Response
GET /v1/apy-rates
Current earnings APY rates. Scope:read:earnings
Query parameters
Response
GET /v1/dinari/capabilities
What the user may currently do with tokenized equities (dShares). Scope:read:account
Response
blockedReasons is ordered — render the first entry as the next thing the user should fix. It is empty if and only if canTrade is true.
GET /v1/dinari/us/requirements
What a US-jurisdiction user still owes before their brokerage KYC can be submitted. Scope:read:account
Returns field names and counts only — never the user’s answers. A non-US user gets isUsCustomer: false and an empty, already-complete requirement set.
Response
There is no write counterpart to this endpoint, by design. The US profile answers and the ten regulatory disclosures are completed by the user in the Moneda app: a consent recorded without the user having personally seen the verbatim document is not a consent, and the row carries an IP and timestamp that a broker-dealer treats as a signature. Use this endpoint to explain what is outstanding and send the user to
onboardingPath.GET /v1/dinari/market-hours
The US equity session clock. No scope required: this is the public exchange calendar and carries no account data. Responsewindows are ISO instants for the trading day named by cycleEtDate. On a weekend or holiday that is the next trading day, so there is always a concrete cycle to show. Render the instants in the reader’s own timezone.
GET /v1/dinari/orders/free-trade-allowance
Commission-free stock trades left in the current window, without quoting an order. Scope:read:account
Response
resetsAt rather than a day of the month.
degraded: true means the count could not be read and the values are a fail-open default. Say so; do not present them as fact. upgrade is populated only once the allowance is spent, and names the cheapest higher plan whose allowance would still have covered this window.
GET /v1/earnings/time-series
Daily time series of earnings and balance for a Morpho or YO vault account, used for charting yield over time. Scope:read:earnings
Query parameters
Response
Account Info
GET /v1/wallet
Your smart wallet address on Base. Scope:read:account
Query parameters
Response (full)
?view=lite) — ~76% smaller
GET /v1/virtual-accounts
IBAN and ACH virtual account details for receiving transfers. Scope:read:virtual_accounts
Query parameters
Response (full)
active, pending, or not_registered.
Response (?view=lite) — ~78% smaller
GET /v1/virtual-accounts/limits
Remaining spending limit per direction on a rolling 52-week window, plus enhanced-due-diligence (EDD) status. Scope:read:virtual_accounts
Crossing a limit does not reject a transfer — the banking partner pauses it and gives the user 24 hours to supply a Source-of-Wealth document before it is returned. Check this before proposing a large deposit or withdrawal.
Response
threshold: null means the customer has no enforced cap — not that the value is unknown. Limits are per direction and are not a combined budget: a customer may use their full limit on deposits and on withdrawals in the same window. Thresholds are personalised per customer (derived from declared income), so never hard-code one — always read it here.
GET /v1/virtual-accounts/settlement-estimate
The date a US bank (ACH) transfer settles. Scope:read:virtual_accounts
Accounts for the 3:00 PM ET same-day cutoff, weekends, and US federal bank holidays — a transfer sent the afternoon before Thanksgiving does not arrive the next day. USD/ACH only; no equivalent published cutoff exists for EUR/SEPA.
Query parameters
Response
settlesOn is a calendar date in the bank’s timezone (ET). delayedByHoliday is true when a bank holiday, not merely a weekend, pushed the date out.
GET /v1/accounts
Your saved external wallets and bank accounts. Scope:read:external_accounts
Query parameters
Response (full)
GET /v1/contacts
Your saved contacts (Moneda users, external wallets, and bank accounts). Scope:read:contacts
Query parameters
Response
GET /v1/settings
Your app preferences. Scope:read:settings
Response
GET /v1/passkeys
Your authentication passkeys. Scope:read:passkeys
Query
Response (
target=WALLET)
kind tells a backup apart from the key you signed up with, and onchainStatus
says whether it can actually sign yet: a pending backup is registered but its
add-owner transaction has not confirmed.
target=LOGIN)
The credential id is masked and the public key is never returned.
This endpoint reports which keys exist, not which one signs next. The
preferred signing key is chosen on the user’s own device and is never stored
server-side, so no API can report it. Don’t infer it from
kind or ordering.PATCH /v1/passkeys/{id}/label
Rename one of your passkeys. Scope:write:profile
Cosmetic only — it cannot add, remove, or weaken a credential. Use the id from
GET /v1/passkeys. target is WALLET for a smart-account passkey or LOGIN for an
email login passkey. A null or empty label clears the nickname so the derived provider
name is shown again. Labels are capped at 40 characters and are not required to be unique.
Body
404 when the id does not belong to you.
GET /v1/recovery-contacts
Your recovery guardians. Scope:read:recovery
Response
Recovery emails (ZK email recovery)
The recovery-emails endpoints surface the email addresses set up for ZK email-based account recovery. Mutations (invite, accept, recover) require a passkey-signed UserOp from the mobile app and are not exposed over REST. All four endpoints share theread:recovery scope and accept an optional accountId query parameter — when omitted, the call defaults to the authenticated user’s main LOCAL account.
GET /v1/recovery-emails
List recovery emails set up for the account. Query parameters
Response
message field instead of an empty array.
GET /v1/recovery-emails/{id}
Single recovery email lookup by id. 404 if not found or not owned by this user (unified to prevent existence leakage). Path parameters
Query parameters
Returns the same shape as the list rows, plus the on-chain
accountAddress the email protects.
GET /v1/recovery-config
Recovery configuration for an account: accepted recovery emails, total weight, and the threshold required to approve a recovery. Query parameters
Response
threshold is a fixed value (currently 100) that must match the on-chain Universal Email Recovery Module configuration. Recovery is approvable when totalWeight >= threshold.
GET /v1/recovery-status
Most recent recovery request snapshot for the account. Reads from the database only — agents tolerate the slight lag while the cron job syncs on-chain state. The mobile app additionally polls on-chain. Query parameters
Response (no recovery in flight)
hasActiveRecovery is true only for the active states (initiated, threshold_met, executing); terminal states (cancelled, completed, expired, failed) flip it back to false while the latest recovery details are still returned for context. Recovery email addresses are anonymized to first-letter***@domain in the active payload.
Notifications
GET /v1/notifications
Paginated in-app notifications inbox, newest first. Scope:read:notifications
Query parameters
Response
nextCursor is omitted on the last page. metadata shape varies by type — agents should treat it as opaque unless they recognise the type. Mark-as-read / dismiss / clear-all are tied to the active mobile push session and stay in tRPC; the REST surface is read-only.
GET /v1/notifications/unread-count
Unread notification count. Scope:read:notifications
Response
Sub-accounts (vaults)
Sub-accounts (a.k.a. vaults) are nested Safe smart accounts owned by your main account. The endpoints below are read-only — vault create / top-up / withdraw / freeze / close all require a passkey-signed UserOp from the mobile app. All endpoints require theread:sub_accounts scope.
GET /v1/sub-accounts
List the user’s sub-accounts. Query parameters
Response
GET /v1/sub-accounts/{id}
Single sub-account detail by id. Path parameters
Returns the full sub-account shape including parent + child Safe addresses, members, deployment index, and close timestamp.
GET /v1/sub-accounts/{id}/balance
On-chain balances for a sub-account’s child Safe. Path parameters
Query parameters
Balances are returned as raw bigint strings (6 decimals).
GET /v1/wealth
Aggregate wealth across the main account + every live vault. Scope:read:balances + read:sub_accounts.
Query parameters
Returns per-leg breakdown (wallet + Morpho + YO for the main account; wallet-only for vaults) plus per-currency totals. USDC and EURC are cross-converted using the on-chain Aerodrome rate.
Sessions
API key authentication produces sessions tracked in the database for audit trails. Bearer-token (OAuth) requests don’t create sessions.POST /v1/sessions
Create a session record (typically called by clients that hold long-lived API keys). Scope: depends on the calling channel. Request bodyDELETE /v1/sessions/{sessionId}
End a session. Path parameters
Returns
204 No Content on success.
GET /v1/sessions/active
List active login sessions and connected agents (third-party services). Scope:read:sessions
Response
DELETE /v1/sessions/active/{sessionId}
Terminate a specific active session. Scope:write:sessions
Path parameters
Response
POST /v1/sessions/revoke-all
Terminate all other active sessions, keeping the caller’s current session. Scope:write:sessions
Response
Points & Referrals
GET /v1/points/balance
Your points balance. Scope:read:points
Response
GET /v1/points/activity
Points earning history. Scope:read:points
Query parameters
Response
GET /v1/points/redemption-config
Config for redeeming points into AI credits: the points-per-$1 rate, the minimum redemption, the monthly cap, your current balance, and how much monthly allowance is left. Scope:read:points
Response
POST /v1/points/redeem
Redeem Moneda Points for prepaid AI usage credits. Spends points and grants the matching AI budget atomically, enforcing the minimum, sufficient-balance, and monthly-cap checks. Scope:write:usage_credits
Body
Response
GET /v1/referrals/code
Your referral link and stats. Scope:read:referrals
The referral code is derived from your account (
<username>-<id-prefix>). Set a username first — the code is unavailable until you do.GET /v1/referrals/referees
Friends you’ve referred. Scope:read:referrals
Response
Knowledge Base
These endpoints are public — no authentication required.GET /v1/knowledge/search
Search the FAQ knowledge base. Query parameters
Response
GET /v1/knowledge/categories/
Browse a FAQ category by slug. Path parameters
Response
GET /v1/knowledge/items/
Get a specific FAQ item. Path parameters
Response
Users
GET /v1/users/search
Search Moneda users by username or display name. Scope:read:users
Query parameters
Response
Write Endpoints
PATCH /v1/profile
Update your display name. Scope:write:profile
Request body
PATCH /v1/transactions/{hash}/category
Assign a spending category to a transaction. Scope:write:transactions
Path parameters
Request body
TOP_UP, INVESTMENT, FRIENDS_FAMILY, INTEREST_EARNINGS, SUBSCRIPTIONS, SERVICES, GROCERIES, SHOPPING, RESTAURANTS, TRANSPORT, TRAVEL, UTILITIES, CASH, SALARY, FUEL, EV_CHARGING, GAMBLING, CHARITY_DONATIONS, TAXES, INSURANCE, CARD, HEALTHCARE, GENERAL
Response
PATCH /v1/transactions/{hash}/note
Add or update a note on a transaction. Scope:write:transactions
Path parameters
Request body
POST /v1/transactions/batch/categories
Categorize up to 25 transactions at once. Scope:write:transactions
Request body
POST /v1/transactions/batch/notes
Add notes to up to 25 transactions at once. Scope:write:transactions
Request body
POST /v1/accounts/wallets
Save an external crypto wallet. Scope:write:external_accounts
Request body
confirmed: false first to check for warnings (e.g. if the address belongs to another Moneda user). Then resend with confirmed: true to proceed.
Response
POST /v1/accounts/banks
Save a bank account (EU IBAN or US ACH). Scope:write:external_accounts
Request body (EU)
POST /v1/payments
Initiate a payment. Requires approval in the Moneda app. Scope:write:payments
Request body
Response
GET /v1/payments//status
Check the status of a payment request. Scope:write:payments
Path parameters
Response
PENDING_APPROVAL, APPROVED, COMPLETED, FAILED, EXPIRED, REJECTED
POST /v1/x402-payments
Pay an x402 (HTTP 402 Payment Required) invoice to a wallet address. Requires approval in the Moneda app, then settles on-chain to the resource’spayTo address. Scope: write:payments
Request body
Response
Payment Routing
These endpoints help an agent or client choose a payment corridor and quote the cost before calling
POST /v1/payments. They are provider-agnostic — don’t branch on which underlying processor handles each rail.GET /v1/payment-destinations
List the country, currency, and rail combinations Moneda can pay out to. Each entry includes the required fields you’ll need to collect from the user before callingPOST /v1/payments. Scope: read:external_accounts
Query parameters
GET /v1/payment-quote
Preview the cost, FX rate, and final amount for moving money between two currencies. Provide exactly one ofamountIn (what the user sends) or amountOut (what they want to receive). Scope: read:rates
Query parameters
Receipts
Receipts are user-uploaded files (PDFs, images, structured invoices) the platform OCRs, extracts to structured fields, and optionally auto-matches to a transaction. Bills are the invoice-shaped sibling (AP queue) covered separately below.
GET /v1/receipts
List the user’s transaction receipts, newest first, with extracted summary fields and lifecycle status. Scope:read:receipts
Query parameters: transactionHash (optional), needsReview (true/false, optional), status (optional), limit (default 20, max 100), cursor (optional).
GET /v1/receipts/{receiptId}
Get one receipt with full extracted fields and a presigned S3 download URL valid for ~15 minutes. Scope:read:receipts
GET /v1/receipts/{receiptId}/line-items
List parsed line items on a receipt — description, quantity, unit price, total, tax rate, category. Scope:read:receipts
POST /v1/receipts/{receiptId}/line-items
Add a line item to a receipt. Used after manual extraction review. Scope:write:receipts
PATCH /v1/receipts/line-items/{lineItemId}
Update one line item on a receipt (description, quantity, price, tax rate, category). Scope:write:receipts
DELETE /v1/receipts/line-items/{lineItemId}
Remove one line item from a receipt. Scope:write:receipts
GET /v1/receipts/line-items/search
Search across every line item the user has uploaded (case-insensitive substring on description). Returns matching items + aggregate spend grouped by currency. Optional category and date-range filters. Scope:read:receipts
POST /v1/receipts
Create a receipt row (metadata only; for direct upload use the upload-url + finalize flow). Scope:write:receipts
DELETE /v1/receipts/{receiptId}
Delete a receipt and its line items. Scope:write:receipts
POST /v1/receipts/upload-url
Step 1 of 2 — get a presigned S3 PUT URL to stage a local file. ReturnsuploadUrl, uploadKey, and constraints (size cap, content-type whitelist). The file bytes go directly to S3. Scope: write:receipts
POST /v1/receipts/finalize
Step 2 of 2 — after PUTting the file to S3, finalize the receipt to run OCR + LLM extraction, attempt auto-match to a transaction, and persist line items. Pass theuploadKey from /v1/receipts/upload-url. Scope: write:receipts
POST /v1/receipts/import-url
Import a receipt directly from anhttps:// URL (S3, Drive shared link, public file host). The server fetches behind an SSRF guard — rejects private IPs and non-https. Single call. Scope: write:receipts
POST /v1/receipts/{receiptId}/attach
Link a receipt to a transaction (used after manual review when auto-match didn’t run or was wrong). Scope:write:receipts
POST /v1/receipts/{receiptId}/detach
Unlink a receipt from its transaction. Scope:write:receipts
POST /v1/receipts/{receiptId}/confirm-suggestion
Accept the auto-match suggestion the OCR pipeline proposed. Scope:write:receipts
POST /v1/receipts/{receiptId}/reject-suggestion
Reject the auto-match suggestion (the receipt stays unlinked). Scope:write:receipts
Bills (AP queue)
Bills are the invoice-shaped sibling of receipts. They surface as an accounts-payable queue ordered due-soon-first, and carry merchant + payment routing detail extracted by OCR.
GET /v1/bills
List the user’s bills (AP queue), ordereddueDate ASC NULLS LAST, id DESC. Cursor-paginated; defaults to status=PENDING. Scope: read:receipts
GET /v1/bills/{billId}
Get one bill with full extracted detail — merchant (name, tax id, address), total, currency, due date, invoice number, vendor IBAN/BIC/routing/account, payment status, presigned download URL. Scope:read:receipts
Bewirtungsbelege (German hospitality receipts)
Bewirtungsbelege are an overlay on existing transactions that capture German tax-deductible business-meal detail (occasion, attendees, deductible/non-deductible split). They reference a transaction; the receipt file itself stays in the Receipts table.
GET /v1/bewirtungsbelege
List the user’s Bewirtungsbelege. Each row carries the underlying transaction, date, location, occasion, total/tip/subtotal split, deductible/non-deductible amounts, and signing state. Scope:read:receipts
GET /v1/bewirtungsbelege/{bewirtungsbelegId}
Get one Bewirtungsbeleg with full detail including attendees. Scope:read:receipts
POST /v1/bewirtungsbelege
Create a Bewirtungsbeleg overlay for an existing transaction. Scope:write:receipts
DELETE /v1/bewirtungsbelege/{bewirtungsbelegId}
Delete a Bewirtungsbeleg overlay. The underlying transaction and receipt file are untouched. Scope:write:receipts
Eigenbelege (German self-issued substitute receipts)
Eigenbelege are used when the original receipt for a transaction was lost or never issued. They capture the recipient, amount, and reason for the substitute receipt.
GET /v1/eigenbelege
List the user’s Eigenbelege. Each row carries the linked transaction, recipient name, amount, reason, and signing state. Scope:read:receipts
GET /v1/eigenbelege/{eigenbelegId}
Get one Eigenbeleg with full detail. Scope:read:receipts
POST /v1/eigenbelege
Create an Eigenbeleg overlay for an existing transaction. Scope:write:receipts
DELETE /v1/eigenbelege/{eigenbelegId}
Delete an Eigenbeleg overlay. The underlying transaction is untouched. Scope:write:receipts
Cards
Card endpoints return PCI-redacted metadata only — last four digits, expiry, design, status. Full PAN / CVV / PIN are never available via the API. Freeze and unfreeze run on-chain via the
PausableCardGuard and are fully reversible.GET /v1/cards
List the user’s cards (active, suspended, expired, terminated) with PCI-redacted metadata. Scope:read:cards
GET /v1/cards/{cardId}
Get detailed metadata for one card (status, type, program, currency, expiry, design). ReturnsNOT_FOUND if the card does not exist or does not belong to the caller. Scope: read:cards
POST /v1/cards/{cardId}/freeze
Freeze a card on-chain via thePausableCardGuard. Settlement is blocked at the Roles Module level. Idempotent at the storage level (re-freezing succeeds, but a fresh on-chain tx is submitted on every call). Returns CONFLICT if the card’s on-chain proxy hasn’t been deployed yet. Scope: write:cards
POST /v1/cards/{cardId}/unfreeze
Unfreeze a card on-chain via thePausableCardGuard. Restores settlement. Idempotent at the storage level. Scope: write:cards
Scheduled (Recurring) Transactions
Read + lifecycle (pause/resume) endpoints for scheduled transactions. Create / activate / cancel / edit / renew are NOT exposed via REST — they need a passkey signature on a Smart Sessions install UserOp, which is mobile-app only.
GET /v1/scheduled-transactions
List the user’s scheduled (recurring) transactions. Filter by status. Scope:read:transactions
GET /v1/scheduled-transactions/{id}
Get one scheduled transaction by id. Scope:read:transactions
GET /v1/scheduled-transactions/upcoming
List the next scheduled executions across all the user’s schedules. Scope:read:transactions
GET /v1/scheduled-transactions/{id}/history
List past executions for one schedule. Scope:read:transactions
POST /v1/scheduled-transactions/{id}/pause
Pause execution of a schedule (backend-only state flip; no on-chain change). Scope:write:transactions
POST /v1/scheduled-transactions/{id}/resume
Resume execution of a paused schedule. Returns the newnextExecutionAt, which is always in the future — an execution window that elapsed while the schedule was paused is skipped, never run retroactively. Fails with 422 if the schedule’s end date has already passed. Scope: write:transactions
Agent Sessions
Read + lifecycle (pause/resume/revoke) endpoints for scoped autonomous agent sessions — a bounded mandate an agent can spend against without per-payment approval. Create / execute and the passkey-bound install are served separately. Both scopes are opt-in (not granted by default).
POST /v1/agent-sessions
Create a scoped autonomous payment session. Does NOT activate — returns a counterfactual child Safe address and an activation link the user opens in the Moneda app to install the on-chain policy with a passkey. Body:recipient, currency (USD/EUR), maxAmountPerExecution, maxAmountPerPeriod (user-facing units), periodSeconds, optional expiresAt, fundingAmount. Scope: write:agent_sessions
GET /v1/agent-sessions
List the user’s agent sessions, newest first, with status, spending policy, and remaining period cap. Optionalstatus query filter. Scope: read:agent_sessions
POST /v1/agent-sessions/{id}/payments
Execute a payment within an ACTIVE session’s on-chain policy — no per-payment approval. Body:recipient, amount (user-facing units), currency, optional idempotencyKey for safe retries. Scope: write:agent_sessions
GET /v1/agent-sessions/{id}
Get one agent session by id, including its 5 most recent executions. Scope:read:agent_sessions
POST /v1/agent-sessions/{id}/pause
Pause an active session (backend-only flip; halts execution, reversible via/resume). Scope: write:agent_sessions
POST /v1/agent-sessions/{id}/resume
Resume a manually-paused session. Auto-paused sessions need their underlying condition cleared first. Scope:write:agent_sessions
POST /v1/agent-sessions/{id}/revoke
Revoke a session — immediately and permanently halts all execution. The on-chain uninstall is completed separately in the Moneda app. Scope:write:agent_sessions
Usage Credits
POST /v1/usage-credits/purchase
Redeem a completed top-up payment to Moneda for prepaid AI usage credits. The amount is read from the confirmed on-chain payment (never from input), converted to USD budget, and granted exactly once — re-calling with the same hash is safe (idempotent). The payment is already finished, so there is nothing more to approve. Body:transactionHash. Scope: write:usage_credits
Response
PATCH /v1/usage-credits/monthly-limit
Set or clear the monthly spend limit on AI usage credits — the ceiling on how much of the prepaid balance may be consumed per calendar month (resets the 1st, UTC). Body:monthlyLimitUsd (number 0–100000, or null for unlimited). Scope: write:usage_credits
Response
Subscriptions
Read + invoice-generation surface for subscription billing. The write surface (subscribe / cancel / change plan) stays in tRPC for now — it needs on-chain Smart Session ceremonies that don’t fit a synchronous REST request. Gated by the
ENABLE_BALANCE_PAY_SUBSCRIPTIONS feature flag in the services layer (a disabled flag surfaces as 403).GET /v1/subscriptions/charges
Cursor-paginated list of the authenticated user’s subscription charges (SUBSCRIPTION_CHARGE rows), newest first. Scope: read:subscriptions
POST /v1/subscriptions/charges/{chargeId}/invoice
Idempotently generate (and upload) the ZUGFeRD plan-invoice PDF for a charge and return a 1-hour presigneddownloadUrl. Re-calling for the same charge reuses the existing invoice. Returns 404 if the charge doesn’t exist or isn’t owned by the caller. Scope: read:subscriptions
Platform (Management API)
The Platform Management API (/v1/platform/*) lets developers manage their organization, workspaces, members, invites, and platform API keys. These endpoints are authorized by the calling user’s organization role (owner / admin / developer / billing / compliance / member), not by MCP scopes. See the Moneda Platform for the full model.
POST /v1/platform/organizations
Create an organization. The caller is seated as itsOWNER. Body: name, slug.
GET /v1/platform/organizations
List the organizations the caller is an active member of, with their role in each.POST /v1/platform/organizations/{orgId}/workspaces
Create a workspace under an organization. Requires a key-manager role (owner / admin / developer). Body:name, slug.
GET /v1/platform/organizations/{orgId}/workspaces
List the workspaces in an organization.POST /v1/platform/organizations/{orgId}/members
Add (or re-activate) a member by user id. Requires a member-manager role (owner / admin); only an owner may grant or modify theOWNER role. Body: userId, role.
GET /v1/platform/organizations/{orgId}/members
List the members of an organization with their roles.POST /v1/platform/organizations/{orgId}/invites
Invite a member by email. Requires a member-manager role. Returns the raw invite token once. Body:email, role.
GET /v1/platform/organizations/{orgId}/invites
List an organization’s invites with their status (pending / accepted / expired). Never exposes the token hash.POST /v1/platform/invites/accept
Accept an invite. Body: the raw invitetoken. Seats the caller as an organization member.
POST /v1/platform/workspaces/{workspaceId}/keys
Issue a workspace-scoped platform API key. Requires a key-manager role. The raw secret is returned exactly once. Body:name, scopes (money-movement scopes are not available on platform keys), optional mode. mode: "live" (default) mints an mnd_live_… key billed against org credits; mode: "test" mints an mnd_test_… sandbox key — it never decrements credits, never calls paid upstreams, and uses separate rate buckets. (Sandbox tool calls are served as deterministic fixtures; tool execution over platform keys — live and sandbox — ships with the tool API and is not yet available.) Live and sandbox keys have independent per-workspace caps. The response sandbox flag reflects the key’s mode.
GET /v1/platform/workspaces/{workspaceId}/keys
List a workspace’s platform API keys (metadata only — never the secret).POST /v1/platform/keys/{keyId}/rotate
Rotate a platform key: mints a replacement and puts the old key on a grace window so it can be swapped with zero downtime. Requires a key-manager role.DELETE /v1/platform/keys/{keyId}
Revoke a platform key immediately. Requires a key-manager or compliance role.POST /v1/platform/organizations/{orgId}/limits
Create or reconfigure a spend/rate limit. Requires a member-manager role (owner / admin). Body:scope (ORG/WORKSPACE/KEY), targetId, limitType (SPEND_HARD/SPEND_SOFT/RATE_RPM/RATE_TPM/RATE_RPD), value, optional windowSeconds (rolling window; defaults to the calendar month for spend), and optional notifyThresholdPct (1–99). Upserts on (scope, targetId, limitType).
GET /v1/platform/organizations/{orgId}/limits
List every limit configured for the org (its own, plus workspace- and key-scoped limits). Any member may read.DELETE /v1/platform/organizations/{orgId}/limits/{limitId}
Remove a limit. Requires a member-manager role.POST /v1/platform/workspaces/{workspaceId}/webhooks
Register a webhook endpoint for a workspace. Requires a member-manager role. Body:url (https only, and must resolve to a public address — loopback/private/link-local targets are rejected at registration and re-checked at every delivery), optional description, and enabledEvents (one or more of the event catalog below). The signingSecret is returned exactly once — store it to verify signatures.
GET /v1/platform/workspaces/{workspaceId}/webhooks
List a workspace’s webhook endpoints (metadata only — never the signing secret).PATCH /v1/platform/webhooks/{webhookId}
Update an endpoint’surl, description, enabledEvents, or status (ENABLED/DISABLED). Requires a member-manager role.
DELETE /v1/platform/webhooks/{webhookId}
Delete a webhook endpoint (cascades its pending deliveries). Requires a member-manager role. Event catalog:usage.threshold_reached, usage.limit_exceeded, usage.rate_limited, credit.low, credit.exhausted, key.created, key.revoked.
Signature verification. Each delivery is a POST with headers X-Moneda-Event, X-Moneda-Delivery, X-Moneda-Timestamp, and X-Moneda-Signature. Verify by computing HMAC-SHA256(signingSecret, "v0:" + timestamp + ":" + rawBody) (hex) and comparing against X-Moneda-Signature; reject timestamps outside a few minutes to prevent replay.
Delivery is at-least-once. A retry (or an overlapping dispatch of a still-in-flight delivery) can send the same event more than once. Deduplicate on X-Moneda-Delivery (unique per delivery attempt) or the event’s id, and make your handler idempotent. Return a 2xx promptly; any other status is retried with exponential backoff up to 6 attempts.
GET /v1/platform/organizations/{orgId}/audit-log
Read the organization audit log (policy-changing actions: key/limit/webhook/member changes), newest first. Restricted to owner / admin / compliance roles. Query: optionalaction filter, before (opaque cursor — pass a prior response’s nextBefore), limit (default 50, max 200). Response includes nextBefore for keyset pagination.
GET /v1/platform/organizations/{orgId}/usage
Read the organization’s metered request log (one row per billed call), newest first. Any member may read. Query: optionalworkspaceId, apiKeyId, tool filters, before (opaque cursor — pass a prior response’s nextBefore), limit (default 50, max 200). Money fields (costUsd, upstreamCostUsd) are strings; response includes nextBefore.
GET /v1/platform/pricing
The machine-readable rate card: one row per tool withunitPriceUsd, markupMultiplier, and the effective pricePerUnitUsd (unit × markup), plus unit (PER_CALL/PER_1K_TOKENS/PER_GB_DAY), category, and scope. Money fields are decimal strings. This is the global default table.
GET /v1/platform/organizations/{orgId}/contract
Read the org’s enterprise contract (committed spend, term, SLA tier, dedicated-capacity flag, legal-doc references) plus itsbillingMode and dataResidency. Returns null if the org has no contract. Any member may read.
PUT /v1/platform/organizations/{orgId}/contract
Create or update the enterprise contract terms. Requires a member-manager role. Body (all optional):status (DRAFT/ACTIVE/EXPIRED/TERMINATED), committedAmountUsd, termStart, termEnd, autoRenew, slaTier, dedicatedUpstreamCapacity, legalDocRefs ([{ kind, url, version?, signedAt? }] — pointers to MSA/DPA/SLA, never the documents), dataResidency. Provisioning is sales-led; in production this is a Moneda-admin action.
POST /v1/platform/organizations/{orgId}/billing-mode
Set the org’s billing mode. Requires a member-manager role. Body:billingMode (PREPAID or INVOICED). INVOICED — where usage accrues to a monthly invoice against the contract instead of decrementing prepaid credits — requires an ACTIVE contract.
Error Responses
All errors follow a consistent format:What’s next?
Authentication
Learn how to authenticate your API requests.
OpenAPI Spec
Explore the API interactively with Swagger UI.
Scopes
See which scopes each endpoint requires.
CLI Tool
Use these endpoints from the command line with the Moneda CLI.
