API · 12 operations

Me

The calling key: who it is, its scopes, budgets and limits; preferences and API keys.

get /v1/keys

The account's agent keys (never their secrets)

scope budget:read · listKeys

Returns · 200

{ keys: [{ id, name, scopes, created_at, last_used_at, expires_at, days_left, status, expiry_policy, revoked, created_by, mine }] }. status is active, expiring (14 days or fewer), expired or revoked. mine says whether this session may revoke it: the person who minted it, or an admin. Session principals only: a request made with an API key is refused with 403. Keys are Clerk's; this lists them for the person's account (their user, or the organization the session is in).

Example

curl 'https://api.mintro.money/v1/keys' \ -H "Authorization: Bearer $MINTRO_KEY"

Errors · besides 401, 429, 500

  • 403

    forbidden: The key is valid but lacks the scope this call needs. Ask the human to mint a key with the scope named in the message.

  • 503

    keys_unavailable: Key minting is not available on this instance. The human can still create a key in the app's Account section, or ask support.

post /v1/keys

Mint a key for one agent; the secret is in this response and never again

scope budget:write · createKey

Body · JSON

  • name string · required · ≤ 64 chars

  • scopes "budget:read" | "budget:write" | "connections:read" | "connections:write" | "webhooks:manage"[]

Returns · 201

{ id, name, scopes, secret, created_at }. One key per agent is the convention (claude, chatgpt, kimi, grok, or <person>-<agent> on a shared budget) so the outbox and the register can say which agent did what. A key never holds more than the session minting it: the caller's scopes are the ceiling, and omitting scopes means the same set (a household member's key cannot link banks or manage webhooks; an admin's or a personal account's can). Asking for more is 403. Every key expires ninety days after its first use: the agent then gets a 401 whose code is key_expired, telling it to ask you to rotate. Session principals only: an API key cannot mint a key (403).

Example

curl -X POST 'https://api.mintro.money/v1/keys' \ -H "Authorization: Bearer $MINTRO_KEY" \ -H 'Content-Type: application/json' \ -d '{ "name": "<name>" }'

Errors · besides 401, 429, 500

  • 400

    validation_failed: The request body or query is malformed. The message names the offending field; fix it and retry.

  • 403

    forbidden: The key is valid but lacks the scope this call needs. Ask the human to mint a key with the scope named in the message.

  • 409

    idempotency_conflict: This Idempotency-Key was used for a different request, or the first request is still in flight. Retry the in-flight case after a second; use a fresh key for a genuinely different request.

  • 503

    keys_unavailable: Key minting is not available on this instance. The human can still create a key in the app's Account section, or ask support.

delete /v1/keys/{id}

Revoke a key

scope budget:write · revokeKey

Parameters

  • id path · string · required

Returns · 200

{ id, revoked: true }. The agent holding it gets 401 within a minute (the verify cache). Only the person who minted the key, or an admin, may revoke it (403 otherwise). Session principals only.

Example

curl -X DELETE 'https://api.mintro.money/v1/keys/<id>' \ -H "Authorization: Bearer $MINTRO_KEY"

Errors · besides 401, 429, 500

  • 403

    forbidden: The key is valid but lacks the scope this call needs. Ask the human to mint a key with the scope named in the message.

  • 404

    not_found: No such record on this budget. Re-read GET /v1/budgets/{id} (or the relevant list) for current ids rather than reusing a remembered one.

  • 409

    idempotency_conflict: This Idempotency-Key was used for a different request, or the first request is still in flight. Retry the in-flight case after a second; use a fresh key for a genuinely different request.

  • 503

    keys_unavailable: Key minting is not available on this instance. The human can still create a key in the app's Account section, or ask support.

post /v1/keys/{id}/rotate

Rotate a key: a successor with the same name and scopes, the old one ended

scope budget:write · rotateKey

Parameters

  • id path · string · required

Body · JSON

  • grace_days integer · required · ≥ 0 · ≤ 7 · default 0

Returns · 201

{ id, name, scopes, secret, created_at, expires_at, replaces, old_key_expires_at }. The new secret is in this response and never again. With grace_days: 0 (the default) the old key stops within a minute; up to 7 days of grace keeps it alive while the agent's config is updated. Only the person who minted the key, or an admin, may rotate it. Session principals only.

Example

curl -X POST 'https://api.mintro.money/v1/keys/<id>/rotate' \ -H "Authorization: Bearer $MINTRO_KEY" \ -H 'Content-Type: application/json' \ -d '{ "grace_days": 0 }'

Errors · besides 401, 429, 500

  • 400

    validation_failed: The request body or query is malformed. The message names the offending field; fix it and retry.

  • 403

    forbidden: The key is valid but lacks the scope this call needs. Ask the human to mint a key with the scope named in the message.

  • 404

    not_found: No such record on this budget. Re-read GET /v1/budgets/{id} (or the relevant list) for current ids rather than reusing a remembered one.

  • 409

    idempotency_conflict: This Idempotency-Key was used for a different request, or the first request is still in flight. Retry the in-flight case after a second; use a fresh key for a genuinely different request.

  • 503

    keys_unavailable: Key minting is not available on this instance. The human can still create a key in the app's Account section, or ask support.

get /v1/preferences

How this caller likes the live app: notes on, auto-hide, for how long, the Community door, and cashflow on Budget

scope budget:read · getPreferences

Returns · 200

{ live_toasts, live_toast_auto_hide, live_toast_seconds, community_unread_marker, budget_cashflow, updated_at }. Per caller on this account (a person on a shared budget has their own), never per budget. live_toasts is whether the app shows a note at the corner when an agent or another person changes something; live_toast_auto_hide whether the note leaves on its own; live_toast_seconds after how long (5, 10, 15, 30, 60 or 300). community_unread_marker is whether the Community door goes bold with a dot when there is something new there. budget_cashflow is whether the Budget screen shows the cashflow line (safe to spend, lowest, the chart) above the envelopes; off is the budget alone, and the line is still on Cashflow and Accounts. Defaults on / on / 15 / on / on until something is set; updated_at is null while the defaults show.

Example

curl 'https://api.mintro.money/v1/preferences' \ -H "Authorization: Bearer $MINTRO_KEY"

Errors · besides 401, 429, 500

  • 403

    forbidden: The key is valid but lacks the scope this call needs. Ask the human to mint a key with the scope named in the message.

patch /v1/preferences

Change how the live app shows itself to this caller

scope budget:write · setPreferences

Body · JSON

  • live_toasts boolean

  • live_toast_auto_hide boolean

  • live_toast_seconds 5 | 10 | 15 | 30 | 60 | 300

  • community_unread_marker boolean

  • budget_cashflow boolean

Returns · 200

The preferences after the write, same shape as GET. Every field optional, at least one. A person asking you to "keep those notes up longer" means live_toast_seconds; "stop them" means live_toasts: false; "stop telling me Community has new posts" means community_unread_marker: false; "take the cashflow chart off my budget" means budget_cashflow: false, and "put it back" true. Nothing here touches the money in a budget.

Example

curl -X PATCH 'https://api.mintro.money/v1/preferences' \ -H "Authorization: Bearer $MINTRO_KEY" \ -H 'Content-Type: application/json' \ -d '{ "live_toasts": true, "live_toast_auto_hide": true }'

Errors · besides 401, 429, 500

  • 400

    validation_failed: The request body or query is malformed. The message names the offending field; fix it and retry.

  • 403

    forbidden: The key is valid but lacks the scope this call needs. Ask the human to mint a key with the scope named in the message.

  • 409

    idempotency_conflict: This Idempotency-Key was used for a different request, or the first request is still in flight. Retry the in-flight case after a second; use a fresh key for a genuinely different request.

get /v1/me/profile

This person's Community profile: on or off, username, the line, the counts they show

scope budget:read · getMyProfile

Returns · 200

{ community_on, username, show_counts, line, since, counts, counts_at, updated_at, media: { images, gifs } }. media says whether this deployment takes pictures and GIFs in posts. Off (the default) has no username and shows nothing to anyone. since is the month the account was made. counts is the person's own four streaks as the public page would show them (filed, funded, agreed, ahead, each { current, longest, unit }), refreshed from GET /v1/streaks when this is read, at most hourly, and null while streaks are off. Made as a person: a key minted in the app answers for the person who minted it; any other key is refused as no person.

Example

curl 'https://api.mintro.money/v1/me/profile' \ -H "Authorization: Bearer $MINTRO_KEY"

Errors · besides 401, 429, 500

  • 403

    forbidden: The key is valid but lacks the scope this call needs. Ask the human to mint a key with the scope named in the message.

    no_person: Community writes are made as a person. This key was not minted by one in the app, so there is nobody to post as. The human mints a key at Settings → Agents and uses that one, or acts in the app themselves.

patch /v1/me/profile

Turn Community on or off, set the username, the line, and whether counts show

scope budget:write · updateMyProfile

Body · JSON

  • username string · matches ^[a-z0-9_]{4,64}$

  • community_on boolean

  • show_counts boolean

  • line string | null · ≤ 140 chars

Returns · 200

The profile after the write, same shape as GET. Every field optional, at least one. Turning on needs a username, here or already set; a username is 4–64 lowercase letters, digits or underscores, unique across Mintro (Clerk holds it), and a taken one is refused as such. line is at most 140 characters of plain text, null to clear. Turning off takes the name, the line and the counts off everything at once; posts stay and read as "a former member". Nothing here touches the budget, and nothing here can carry an amount.

Example

curl -X PATCH 'https://api.mintro.money/v1/me/profile' \ -H "Authorization: Bearer $MINTRO_KEY" \ -H 'Content-Type: application/json' \ -d '{ "username": "<username>", "community_on": true }'

Errors · besides 401, 429, 500

  • 400

    validation_failed: The request body or query is malformed. The message names the offending field; fix it and retry.

  • 403

    forbidden: The key is valid but lacks the scope this call needs. Ask the human to mint a key with the scope named in the message.

    no_person: Community writes are made as a person. This key was not minted by one in the app, so there is nobody to post as. The human mints a key at Settings → Agents and uses that one, or acts in the app themselves.

  • 409

    idempotency_conflict: This Idempotency-Key was used for a different request, or the first request is still in flight. Retry the in-flight case after a second; use a fresh key for a genuinely different request.

    username_taken: That username belongs to someone else. Ask the human for another; usernames are 4–64 characters of lowercase letters, digits and underscores.

get /v1/me/founder-claim

The founder seat this budget holds, and whether it is on the wall as you

scope budget:read · getMySeat

Returns · 200

{ number, claimed, claimed_by_me }, or null when this budget holds no seat. The seat belongs to the household that bought it; a person claims it, once, onto their own profile.

Example

curl 'https://api.mintro.money/v1/me/founder-claim' \ -H "Authorization: Bearer $MINTRO_KEY"

Errors · besides 401, 429, 500

  • 403

    forbidden: The key is valid but lacks the scope this call needs. Ask the human to mint a key with the scope named in the message.

    no_person: Community writes are made as a person. This key was not minted by one in the app, so there is nobody to post as. The human mints a key at Settings → Agents and uses that one, or acts in the app themselves.

post /v1/me/founder-claim

Put your name on the wall: claim this budget's founder seat onto your profile

scope budget:write · claimFounderSeat

Returns · 200

{ number, claimed: true, claimed_by_me: true }. Needs Community on (the wall shows your username and your line), the household's admin role when there is one, and a seat nobody else in the household claimed. Idempotent for the same person.

Example

curl -X POST 'https://api.mintro.money/v1/me/founder-claim' \ -H "Authorization: Bearer $MINTRO_KEY"

Errors · besides 401, 429, 500

  • 400

    validation_failed: The request body or query is malformed. The message names the offending field; fix it and retry.

  • 403

    forbidden: The key is valid but lacks the scope this call needs. Ask the human to mint a key with the scope named in the message.

    no_person: Community writes are made as a person. This key was not minted by one in the app, so there is nobody to post as. The human mints a key at Settings → Agents and uses that one, or acts in the app themselves.

  • 404

    not_found: No such record on this budget. Re-read GET /v1/budgets/{id} (or the relevant list) for current ids rather than reusing a remembered one.

  • 409

    idempotency_conflict: This Idempotency-Key was used for a different request, or the first request is still in flight. Retry the in-flight case after a second; use a fresh key for a genuinely different request.

    billing_conflict: The billing state does not allow this: the tenant already holds that plan, founder seats are gone, or the extra-bank count would drop below the banks in use. The message says which; nothing to retry until the human acts.

delete /v1/me/founder-claim

Take your name off the seat; the number stays on the wall

scope budget:write · releaseFounderSeat

Returns · 200

The seat as GET returns it, now unclaimed.

Example

curl -X DELETE 'https://api.mintro.money/v1/me/founder-claim' \ -H "Authorization: Bearer $MINTRO_KEY"

Errors · besides 401, 429, 500

  • 403

    forbidden: The key is valid but lacks the scope this call needs. Ask the human to mint a key with the scope named in the message.

    no_person: Community writes are made as a person. This key was not minted by one in the app, so there is nobody to post as. The human mints a key at Settings → Agents and uses that one, or acts in the app themselves.

  • 409

    idempotency_conflict: This Idempotency-Key was used for a different request, or the first request is still in flight. Retry the in-flight case after a second; use a fresh key for a genuinely different request.

get /v1/me

Who this key is: scopes, budgets, plan limits, rate limit

scope budget:read · getMe

Returns · 200

{ key: { principal, scopes, subject_kind, user_id }, tenant: { tenant_id, name, kind }, budgets: [{ id, name, status, url }], default_budget_id, plan: { id, label, price, connections_included, connections_allowed }, entitlements: { plan, plan_label, features: { bank_sync, goals, assets, webhooks }, limits: { manual_accounts, connections_included, connections_extra, connections_allowed, connections_ceiling }, connections_used, member_blocked, org_role, upgrade_url }, founder: { number } | null, billing: { rail, available, plan_source, customer, checkout, portal, connections }, limits: { ... }, features: { bank_linking_available }, endpoints: { api, mcp, openapi, llms } }. Call this first: it is the cheapest way to learn what the key may do before attempting it. entitlements.features says which gated calls (x-mintro-feature in this document) will be refused with a 402 plan_limit on this plan, and it is where the budget ids come from. A budget is the top-level container and an account may hold several; default_budget_id is set only when exactly one is open (a closed budget never counts against it), and it always names what the literal default will resolve to.

Example

curl 'https://api.mintro.money/v1/me' \ -H "Authorization: Bearer $MINTRO_KEY"

Errors · besides 401, 429, 500

  • 403

    forbidden: The key is valid but lacks the scope this call needs. Ask the human to mint a key with the scope named in the message.