{"openapi":"3.1.0","info":{"title":"Sequence API","version":"1.0.0","description":"The Sequence API gives you programmatic control over your money flows.\nSetup, identity verification, and rule review live in the dashboard; the\nAPI is how your code reads account state and executes money flows.\n\n[![How to get started with Sequence — video walkthrough](https://i.ytimg.com/vi/tNpSjKmWSHI/maxresdefault.jpg)](https://www.youtube.com/watch?v=tNpSjKmWSHI)\n\n▶ **[Watch: how to get started](https://www.youtube.com/watch?v=tNpSjKmWSHI)** — a short\nwalkthrough from signup to your first API call.\n\n\n## Setup\n\nBefore your first API call:\n\n1. **Create an account** at [app.getsequence.io](https://app.getsequence.io)\n   and complete identity verification (KYC for individuals, KYB for businesses).\n2. **Connect your bank accounts** via one of the supported providers.\n3. **Create rules** (optional — you can also create them via the API with the\n   `CREATE_AND_EDIT_RULES` permission). A rule is a money flow that runs\n   automatically — a trigger says *when* to run, optional conditions say\n   *whether* to act, and actions say *what* to do (move, split, allocate).\n   Rules must be enabled by a human before they can run.\n4. **Generate an API key** under Settings → API Keys. Keys belong to your\n   Sequence account and carry an explicit set of permissions. You control what\n   a key can do: limit it to specific actions, to specific accounts and rules,\n   cap the amount it can move, or require in-app human approval for any money\n   movement — see *Human approval for money movement* below.\n\nIf you're connecting an AI assistant rather than writing code, you can skip the\nkey entirely and sign in with **OAuth** over the MCP server — no credential to\ngenerate, copy, or store. See *Connect via MCP* below.\n\nNeed help? Join the [Sequence Discord](https://discord.gg/kHP4AJpcyA) and\nask in the `#api` channel, or [contact us](https://home.getsequence.io/contact)\nwith any questions.\n\n\n## Authentication\n\nAll API requests authenticate with a Bearer token:\n\n```\nAuthorization: Bearer YOUR_API_KEY\n```\n\nEach key carries a list of permissions. Every permission names what the\nkey is allowed to do and which resources (accounts or rules) it applies\nto. A request that asks for something outside the key's permissions\nreturns `403 Forbidden`. The full permissions table is in the\nAuthentication panel on the right.\n\nNever expose API keys in client-side code or commit them to source control.\nA key whose money-movement permissions have approval switched off can move\nmoney unattended, so it carries the same power as your password: only hand it\nto agents and services you trust, and revoke it from **Settings → API Keys**\nthe moment you think it's exposed.\n\nThe REST API authenticates with API keys only. The MCP server additionally\naccepts **OAuth**, where permissions aren't key-managed but built in and\nderived from the signed-in member's role: full read access, creation of rules\nthat land inactive, and money movement that always requires in-app human\napproval. See *Connect via MCP* below.\n\n\n## One key per agent\n\nWe recommend creating a **dedicated API key for each agent, automation, or\nintegration** rather than reusing one broad key across everything.\n\nWhy this matters:\n\n- **Revocation.** Rotating or revoking one agent's key doesn't take down every\n  other automation you've wired up.\n- **Audit.** The audit log attributes each call to the key that made it. One key\n  per purpose makes the log readable.\n- **Rate-limit isolation.** The 100 req/min limit is per key. A runaway agent\n  can't starve your other integrations of budget if they each carry their own key.\n- **Least privilege.** Scope each key to only the accounts and rules its owner\n  needs to touch.\n\nSuggested naming pattern: `<tool>-<purpose>`, e.g. `claude-rule-payroll`,\n`n8n-incoming-funds`, `zapier-balance-export`.\n\n\n## Human approval for money movement\n\nA money-movement permission can require that a human approves each action\nbefore it executes. The API call still succeeds, but it registers a *proposal*:\nnothing moves until a person approves it in the Sequence app.\n\nWhere it applies:\n\n- **API keys** — configured per key, per permission, when you create the key\n  under **Settings → API Keys**: the \"require approval before execution\" option\n  on `TRIGGER_RULES` and `MANUAL_TRANSFER`. It **defaults to on**. Read\n  permissions have nothing to gate, so the option appears only on those two.\n- **MCP over OAuth** — always required, and not configurable. An OAuth caller's\n  permissions are built in rather than key-managed, so money movement is\n  approval-gated by construction (see *Connect via MCP* below).\n\n### What the caller sees\n\nWith approval required, `POST /transfers` and `POST /rules/{id}/trigger` still\nsucceed, but the resource comes back awaiting a human instead of queued for\nexecution:\n\n```json\n{\n  \"data\": {\n    \"id\": \"c4a8e3b7-5d9f-4f1a-8e3d-12345abcdef0\",\n    \"status\": \"APPROVAL_PENDING\",\n    \"reasonForApproval\": \"Vendor invoice #4471, due Friday\",\n    \"approvalUrl\": \"https://app.getsequence.io/?approvalTransferId=c4a8e3b7-5d9f-4f1a-8e3d-12345abcdef0\"\n  },\n  \"requestId\": \"req_...\"\n}\n```\n\n`APPROVAL_PENDING` is a success status, not an error condition.\n\n`approvalUrl` opens a focused approve/deny prompt in the Sequence app.\nSequence also notifies the organization's owner and co-owners by email and SMS\nwhen a request is registered, so approval doesn't depend on your application\nrelaying the URL. Poll `GET /transfers/{id}` or\n`GET /rules/{ruleId}/executions/{executionId}` for the outcome:\n\n| Outcome | Transfer status | Rule execution status |\n|---|---|---|\n| Approved | Proceeds as normal — `PROCESSING` → `COMPLETE` | Proceeds as normal — `IN_PROGRESS` → `EXECUTED` |\n| Denied | `APPROVAL_DENIED` | `APPROVAL_DENIED` |\n| No decision within 24 hours | `APPROVAL_DENIED` | `APPROVAL_DENIED` |\n\nA single terminal status covers both ways an approval can fail, so\n`APPROVAL_DENIED` is the only status you need to watch for to know a request\nwill never run. It doesn't distinguish a human's denial from an expiry — if you\nneed that, read the approval record itself. Re-requesting means a new call with\na fresh `idempotency-key`.\n\nAn owner or co-owner can approve or deny; viewers cannot.\n\n### The approval reason\n\nBoth endpoints accept a `reasonForApproval` string in the request body. It's\nshown to the approver in the app and included in the email and SMS, and it's\nechoed back on the resource as `reasonForApproval`. Without it the approver\nsees only the accounts and the amount, which is usually not enough context to\napprove on.\n\nDry runs are the one exception: a `simulation: true` call is never gated, since\nit moves no money and creates nothing to approve. See *Testing* below.\n\n\n## Connect via MCP\n\nSequence runs a [Model Context Protocol](https://modelcontextprotocol.io)\nserver, so AI assistants can call the API directly (list accounts, create\ntransfers, trigger rules, and more) without you writing any integration\ncode. Every endpoint in this reference is exposed as an MCP tool\nautomatically, as well as other useful tools, so the tool set stays in\nlockstep with the API.\n\n- **Server URL:** `https://app.getsequence.io/api/mcp`\n- **Transport:** Streamable HTTP\n- **Authentication:** OAuth *or* an API key — see below.\n\n### Authentication: OAuth or API key\n\n**OAuth.** Point any client that supports MCP OAuth at the server URL with\n*no* credentials. It discovers Sequence's authorization server, opens a\nbrowser, and you sign in to Sequence and consent. There is no key to copy,\npaste, or store, and the connection is tied to your own Sequence user, so the\naudit log attributes each call to you and the MCP client that made it.\n\nOAuth permissions are **built in** — there's no key to scope by hand. Sequence\nmints a token whose permissions are derived from your role in the\norganization and re-derived on every request, so a role change takes effect on\nthat member's next call with nothing to rotate or revoke:\n\n| Your role | Built-in permissions |\n|---|---|\n| Owner, co-owner | Full read access; creating accounts and rules (a new rule stays inactive until a human turns it on); triggering a rule and issuing a manual transfer — **money movement always requires in-app human approval** |\n| Viewer, or any other role | Full read access only |\n\nWhat that means in practice:\n\n- **Money movement is proposal-only.** `TRIGGER_RULES` and `MANUAL_TRANSFER`\n  are granted with approval hardcoded on, and unlike an API key this is not\n  configurable — there's no key-management surface for a built-in token. Every\n  `createTransfer` or `triggerRule` an OAuth assistant issues comes back\n  `APPROVAL_PENDING` and waits for a human (see *Human approval for money\n  movement* above). Both are granted unrestricted as to accounts and amount,\n  so approval is the only control on them.\n- **Rule writes don't execute.** `CREATE_AND_EDIT_RULES` creates rules\n  inactive; a human activates them in the app.\n- **Read-only members stay read-only.** A viewer connecting over OAuth gets\n  the read set and nothing else.\n\nAccess tokens are short-lived; clients that request the advertised\n`offline_access` scope receive a refresh token, so you rarely re-consent.\n\n**API key.** Send the same key as the REST API, as an\n`Authorization: Bearer YOUR_API_KEY` header. A key's permissions apply\nidentically over MCP, so an assistant can only do what its key allows. Unlike\nOAuth, a key can be scoped to specific accounts and rules, can carry a\n`max_amount` cap, and can execute money movement without approval if you\nexplicitly turn that option off. Use a dedicated key per assistant (see *One\nkey per agent* above).\n\n**Claude Code**: run this in your terminal — omit the header to connect over\nOAuth, or include it to use an API key:\n\n```bash\n# OAuth — opens a browser to sign in\nclaude mcp add --transport http sequence https://app.getsequence.io/api/mcp\n\n# API key\nclaude mcp add --transport http sequence https://app.getsequence.io/api/mcp \\\n  --header \"Authorization: Bearer YOUR_API_KEY\"\n```\n\n**Cursor and other Streamable HTTP clients**: point the client at the server\nURL (Cursor stores this in `~/.cursor/mcp.json`). Leave out the header to\nconnect over OAuth — the client prompts you to sign in to Sequence:\n\n```json\n{\n  \"mcpServers\": {\n    \"sequence\": {\n      \"url\": \"https://app.getsequence.io/api/mcp\"\n    }\n  }\n}\n```\n\nOr add the header to use an API key instead:\n\n```json\n{\n  \"mcpServers\": {\n    \"sequence\": {\n      \"url\": \"https://app.getsequence.io/api/mcp\",\n      \"headers\": { \"Authorization\": \"Bearer YOUR_API_KEY\" }\n    }\n  }\n}\n```\n\n**Claude Cowork**: add `https://app.getsequence.io/api/mcp` as a custom\nconnector and sign in to Sequence when prompted — nothing to paste, since it\nconnects over OAuth.\n\nThe [dashboard's MCP page](https://app.getsequence.io/account/mcp) fills in\nyour server name and has the full, copy-paste setup for each client.\n\n### Available tools\n\nThe tools come in two groups: one per endpoint in this reference (named after\nthe operation), plus a few guided setup tools for actions you complete in the\ndashboard. Endpoint tools enforce the same permission as the endpoint, so an\nassistant can only reach what its token allows.\n\nThe list below is the full set. **`tools/list` is filtered to the caller's\npermissions**, so an assistant sees only the tools it can actually use — a\nread-only key, or an OAuth caller who isn't an owner or co-owner, sees neither\n`createTransfer`/`triggerRule` nor `createAccount`.\n\n**Accounts**\n\n- `listAccounts`: list income sources, pods, and connected external accounts\n- `getAccount`: fetch one account with its balance and details (routing and bank account\n  numbers masked to the last 4 digits)\n- `createAccount`: create a pod (savings/goal bucket) or an income source (where outside money lands)\n- `listBeneficiaries`: list the organization's beneficiaries (legal entities that own accounts)\n- `listAccountTransfers`: list transfers for a given account\n\n**Rules**\n\n- `listRules`: list rules\n- `getRule`: fetch one rule with its full steps, conditions, and actions\n- `triggerRule`: run a rule on demand (supports a dry-run simulation)\n- `listRuleExecutions`: list a rule's executions\n- `getRuleExecution`: poll one execution for status and resulting transfers\n\n**Transfers & transactions**\n\n- `createTransfer`: move money between two accounts (supports a dry-run simulation)\n- `listTransfers` / `getTransfer`: list transfers, or fetch one by id\n- `listExternalTransactions`: transactions on connected external accounts (visibility only)\n- `listTransactions`: settled card transactions\n- `listAuditLog`: audit-log entries for the organization\n\n**Guided setup**\n\nThese tools don't move money; they point the assistant (and you) to the right\nplace in the dashboard, since these actions are completed there.\n\n- `createRule`: set up an automation that moves money on a schedule or when funds arrive\n- `connectExternalAccount`: link a bank, credit card, loan, or other outside account\n- `issueCard`: issue a debit card or Omni Card\n- `addUser`: add a co-owner or a viewer (e.g. an accountant) to the account\n- `addBusinessBeneficiary`: set up a business entity so it can own accounts and cards\n- `contactSupport`: reach a human at Sequence support\n\n### Example prompts\n\nOnce connected, ask your assistant things like:\n\n- *\"List my Bank accounts and their balances.\"*\n- *\"Trigger the payroll rule and tell me which transfers it created.\"*\n- *\"Move $50 from Checking to my Tax Savings pod.\"*\n\nThe last two need a money-movement permission, so they require either an OAuth\nconnection as an owner or co-owner, or an API key that carries one. Both\n`createTransfer` and `triggerRule` also take a dry-run flag, so you can ask for\na preview — *\"simulate it first\"* — before anything real happens (see *Testing*\nbelow).\n\n\n## Base URLs\n\n| Environment | URL |\n|---|---|\n| Production | `https://api.getsequence.io/platform/v1` |\n\n\n## Your first request\n\nA quick end-to-end smoke test: list accounts, trigger a rule, then poll\nfor the outcome.\n\n**1. List accounts.** Requires the `READ_ACCOUNTS` permission.\n\n```bash\ncurl https://api.getsequence.io/platform/v1/accounts \\\n  -H \"Authorization: Bearer $SEQUENCE_API_KEY\"\n```\n\n**2. Trigger a rule.** Requires `TRIGGER_RULES` on the rule's ID.\nReturns `202 Accepted` with an `executionId` — execution is asynchronous.\n\n```bash\ncurl -X POST https://api.getsequence.io/platform/v1/rules/$RULE_ID/trigger \\\n  -H \"Authorization: Bearer $SEQUENCE_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -H \"idempotency-key: $(uuidgen)\" \\\n  -d '{}'\n```\n\n**3. Poll for outcome.** Requires `READ_RULES`.\n\n```bash\ncurl https://api.getsequence.io/platform/v1/rules/$RULE_ID/executions/$EXECUTION_ID \\\n  -H \"Authorization: Bearer $SEQUENCE_API_KEY\"\n```\n\n**4. Review the transfers the rule produced.** Requires `READ_TRANSFERS`\non the account. Lists transfers in or out of the given account, newest\nfirst — filter the result to the `ruleExecutionId` from step 3 to find\nexactly what this run moved.\n\n```bash\ncurl https://api.getsequence.io/platform/v1/accounts/$ACCOUNT_ID/transfers \\\n  -H \"Authorization: Bearer $SEQUENCE_API_KEY\"\n```\n\n\n## Testing\n\nThere's no self-serve sandbox stocked with fake money — you build against your\nreal organization and its real accounts. What you get instead are four ways to\nexercise the API, money movement included, at little or no exposure. They\ncompose, and the last three are the ones that tell you how the system really\nbehaves.\n\n\n### Dry runs: `simulation: true`\n\n`POST /transfers` and `POST /rules/{id}/trigger` both accept `simulation: true`.\nThe request runs the real code path and returns a real, readable resource, but\nnothing is ever handed to the banking rails.\n\nWhat a dry run does and doesn't check:\n\n- **Checked, exactly as on a live call.** The token's permission, its account and\n  rule scoping, and its `max_amount` cap; that both accounts exist and can\n  transact; the $1.00 minimum. A rule dry run additionally evaluates the rule's\n  conditions and its per-period transfer limits for real, against **live**\n  transfer history — so a preview reflects the limit budget the rule has actually\n  spent.\n- **Available funds are checked, against the last known balance.** A dry run of an\n  amount the source can't cover comes back terminal with\n  `errorCode: INSUFFICIENT_FUNDS`, on the same status a live transfer from that\n  source would reach: `INCOMPLETE` for a pod or income source, `ERROR` for a\n  connected external account. The balance is whatever we last recorded, not a fresh\n  read — a dry run never asks the institution to re-poll — so a deposit that landed\n  seconds ago may not be reflected yet. Sources the live call doesn't check either\n  aren't gated here: a manual account, or a connected account we hold no balance\n  for, still previews as `COMPLETE`. A rule dry run gates on balance the same way,\n  against whichever base the simulated-balance fields below produce.\n\nDry runs are **never approval-gated** — not on a key that requires approval, not\nover OAuth (see *Human approval for money movement* above). There is nothing to\napprove, so the result comes back directly.\n\n**A simulated transfer** returns on the normal `Transfer` shape, already\nterminal: `status: COMPLETE`, `completedAt` set, `executionMode: SIMULATION`.\n`COMPLETE` here means \"the transfer was computed and recorded\", not \"the money\nlanded\" — no ACH was ever initiated. A dry run the source can't fund is still a\n`201`; the failure rides on the transfer itself, exactly as on a live call.\n\n```json\n{\n  \"data\": {\n    \"id\": \"7f7b52b5-da88-48b6-a63b-c9bcca12d891\",\n    \"amountInCents\": 50000,\n    \"status\": \"COMPLETE\",\n    \"executionMode\": \"SIMULATION\",\n    \"completedAt\": \"2024-04-25T10:00:00Z\"\n  },\n  \"requestId\": \"req_...\"\n}\n```\n\n**A simulated rule trigger** returns `202` with an `executionId`, same as a live\none, and runs asynchronously through the same rule engine. Reading the result takes\ntwo requests, because the execution record tells you what the rule *did* but never\nhow much money it would have moved:\n\n1. Poll `GET /rules/{ruleId}/executions/{executionId}` until `status` is terminal.\n   It reports which step matched (`stepIndexMatched`, or `conditionsNotMet: true`\n   if none did) and how many transfers the run produced (`transfersAttempted`,\n   `transfersCompleted`, and their ids in `transferIds`) — but no amounts.\n2. `GET /transfers/{id}` for each id in `transferIds` to read `amountInCents` and\n   the source and destination.\n\n`transfersAttempted` counts what the engine *calculated*, so it can exceed the\nnumber of ids in `transferIds`: a transfer whose calculated amount came out to zero\nis counted but never created — a `round_down` action with nothing left to round, say,\nor a per-period limit already exhausted. So an empty `transferIds` on an execution\nwith `transfersAttempted: 1` is a real answer — this rule would move nothing — and\nnot a preview that went missing.\n\n**Previewing a balance the account doesn't hold.** Pass the dry-run-only\n`simulatedSourceBalance` (replaces the balance) or `simulatedIncomingFunds` (adds to\nit, modelling a deposit that hasn't landed yet — this is how to preview an\n`ON_FUNDS_TRANSFERRED` rule). `executeAmount` is *not* a simulation knob: it means\nthe same thing on a live trigger as under `simulation: true`, which is precisely what\nmakes a dry run a faithful preview of the live call. See the `simulation` field on\n`TriggerRuleRequest` for how the three combine.\n\nA dry run works on a **deactivated** rule, so you can preview a rule's full\neffect before a human ever turns it on; a live trigger on a disabled rule is\nrejected with `403 RULE_DEACTIVATED`.\n\n**Simulated rows are invisible to reads by default.** Every list endpoint\ndefaults to `executionMode=LIVE`, so pass `executionMode=SIMULATION` (or `ALL`)\non `GET /transfers`, `GET /accounts/{id}/transfers` and\n`GET /rules/{id}/executions` to see your dry runs. The upside of that default:\ndry runs never pollute what your live integrations and reporting read.\n\n\n### Live rails, $1 at a time\n\nA dry run cannot tell you how long an ACH transfer actually takes, and that is\nusually the thing you most need to know. So run the real thing at the minimum\namount — **$1.00 (100 cents)**. You get true settlement timing, real status\ntransitions, and real webhook deliveries, on the whole live system, for a dollar\nof exposure. This is the only way to test end-to-end timelines.\n\n\n### A closed system\n\nGive the integration nowhere to send money. The only way money leaves Sequence\nover the API is a transfer to a connected external account, so if you connect\nnone — or connect them but leave them out of the key's `MANUAL_TRANSFER` and\n`TRIGGER_RULES` resource lists — then every account the key can reach is internal\n(pods and income sources) and no mistake it makes can move money out. Fund one\npod and let your code shuffle that balance as aggressively as you like.\n\n\n### Approval on everything\n\nLeave **require approval before execution** on for `TRIGGER_RULES` and\n`MANUAL_TRANSFER` — it's the default on a new key, and it's mandatory over OAuth.\nEvery money movement your integration attempts then arrives as a proposal you\napprove or deny in the app (see *Human approval for money movement* above), so an\nagent can run wild while you remain the last step. Pass `reasonForApproval` so\neach request explains itself, and actually read it before approving: the prompt is\nthe control, not a formality.\n\n\n## Response format\n\nEvery successful response is wrapped:\n\n```json\n{\n  \"data\": {  },\n  \"requestId\": \"req-42\"\n}\n```\n\nThe `requestId` is the unique handle for the request — include it when\nreporting an issue and we can trace exactly what happened.\n\n\n## Errors\n\nErrors return the matching HTTP status and a body of:\n\n```json\n{\n  \"error\": {\n    \"code\": \"ACCESS_DENIED\",\n    \"message\": \"API key does not have required permissions to access this resource\"\n  }\n}\n```\n\nThe `code` is a stable machine-readable identifier; the `message` is a\nhuman-readable explanation suitable for logs.\n\n**`400 Bad Request`** — Malformed or invalid input.\n\n- `INVALID_PARAMETERS` — the request body fails schema validation.\n- `TRANSFER_SOURCE_NOT_FOUND` / `TRANSFER_DESTINATION_NOT_FOUND` — the source or destination account in a transfer body doesn't exist.\n\n**`401 Unauthorized`** — Missing or invalid API key.\n\n- `UNAUTHORIZED` — no `Authorization` header, or the bearer token couldn't be resolved.\n\n**`403 Forbidden`** — The credential is valid but the action isn't allowed.\n\n- `ACCESS_DENIED` — the key lacks the required permission, or the requested resource is outside the permission's allowed list.\n- `KYC_REQUIRED` — the organization hasn't completed identity verification, so Sequence can't hold or move money for it and it owns no accounts or rules yet. Not a permissions problem: creating or re-scoping a key won't help. The user completes verification in the Sequence app, then the request can be retried.\n- `MAXIMUM_AMOUNT_EXCEEDED` — a manual transfer amount exceeds the permission's `max_amount` cap.\n- `RULE_DEACTIVATED` — attempted to trigger a rule that's disabled in the dashboard.\n- `INVALID_RULE` — the rule's trigger type isn't supported via the API, or the rule has been deleted.\n\n**`404 Not Found`** — The referenced resource doesn't exist or isn't visible to this key.\n\n- `ACCOUNT_NOT_FOUND`, `RULE_NOT_FOUND`, `RULE_EXECUTION_NOT_FOUND`, `TRANSFER_NOT_FOUND` — entity-specific variants.\n- HTTP methods not listed for a given path also return `404 Not Found`, but with a plain-text body (no JSON `Error` envelope). For example, `DELETE /accounts` or `PUT /rules/{id}`.\n\n**`429 Too Many Requests`** — Rate limit exceeded.\n\n- `RATE_LIMIT_EXCEEDED` — the token has exceeded 100 requests per minute. Check the `Retry-After` response header for the number of seconds to wait before retrying.\n\n**`500 Internal Server Error`** — Unexpected server error.\n\n- `UNEXPECTED_ERROR` — catch-all for unhandled exceptions. Include the `requestId` from the response when reporting it.\n\n\n## Idempotency\n\nState-changing endpoints accept an optional `idempotency-key` header.\nSequence remembers the result for 24 hours, so a retry with the same\nkey returns the original response without re-running the operation.\n\n```\nidempotency-key: 7f0e8a52-2b9f-4ae9-9a4b-9d5b0a3e9a48\n```\n\nUse a UUID v4 and generate a fresh one for every distinct intent. This\nmatters most for `POST /rules/{id}/trigger` and `POST /transfers`, where\na retry without an idempotency key can double-spend.\n\n\n## Asynchronous operations\n\n`POST /transfers` and `POST /rules/{id}/trigger` return immediately after the\nwork has been queued. The response includes a resource id with an initial\n`PROCESSING` / `IN_PROGRESS` status — poll `GET /transfers/{id}` or\n`GET /rules/{ruleId}/executions/{id}` to observe the terminal status.\n\n**Eventual consistency.** Reads on async resources are eventually\nconsistent: a very early poll may briefly observe `404\nTRANSFER_NOT_FOUND` / `RULE_EXECUTION_NOT_FOUND` for an id you just\nreceived from a successful POST. Treat such 404s as transient — wait\nbriefly and retry. A 404 on an id you did *not* just receive is final\n(the resource does not exist).\n\nIf a network error interrupts a request before you receive a response, retry\nit using the **same `idempotency-key` value**. The server guarantees\nidempotent processing: if the original request already created the resource,\nthe retry returns the same id. If the original is still in flight, the retry\nreturns `409 TRANSFER_IN_PROGRESS` / `409 RULE_EXECUTION_IN_PROGRESS` — wait\nbriefly and try again.\n\n**Idempotency-Key retention is 24 hours.** Reusing the same key after that\nwindow starts a new operation. Reusing the key within the window with a\n*different* request body returns `400 IDEMPOTENCY_KEY_MISMATCH` — generate\na fresh key for new operations.\n\n\n## Pagination\n\nList endpoints use offset-based pagination via the `page` and `pageSize`\nquery parameters. Responses include a `pagination` object:\n\n```json\n{\n  \"data\": {\n    \"items\": [],\n    \"pagination\": { \"page\": 1, \"pageSize\": 10, \"hasNextPage\": false }\n  },\n  \"requestId\": \"req_...\"\n}\n```\n\nDefaults: `page=1`, `pageSize=10`. Maximum `pageSize` is `100`.\nUse `pagination.hasNextPage` to detect truncation — when `true`, increment\n`page` and re-fetch to retrieve the next batch.\n\n\n## Caching & polling cadence\n\nPick a polling interval that matches how often the underlying data actually\nchanges. Faster polling does not yield fresher data and burns your rate-limit\nbudget (100 requests/minute per key).\n\n| Resource | Upstream refresh | Recommended poll |\n|---|---|---|\n| Balances (`GET /accounts`, `GET /accounts/{id}`) | Connected bank provider refreshes ~once per banking day. The `balance.balanceLastUpdatedAt` timestamp in the response tells you when the snapshot was last updated. | We recommend not polling more often than **every 6 hours**. |\n| Transfers (`GET /transfers`, `GET /accounts/{id}/transfers`) | Updated as ACH events arrive from the provider. | We recommend not polling more often than **every 1 hour**, and **every 6 hours** generally covers all use cases. Use `created_at` filters on subsequent polls to only fetch what's new. |\n| Rule executions (`GET /rules/{id}/executions`, `GET /rules/{id}/executions/{executionId}`) | Updated as the rule runs. | Use exponential backoff after triggering until the status is terminal. |\n\nOn `429 RATE_LIMIT_EXCEEDED`, honor the `Retry-After` response header and back\noff with jitter.\n\n\n## Money & identifiers\n\n- **Amounts** are integers in the account currency's minor unit\n  (cents for USD). `100000` is $1,000.00.\n- **Minimum transfer amount** is **$1.00 (100 cents)**. Applies to both\n  manual transfers (`POST /transfers`) and transfers produced by rule\n  actions. A request to move less than $1.00 is rejected.\n- **Timestamps** are ISO 8601 in UTC (e.g. `2024-04-23T09:15:04Z`).\n- **IDs** are UUIDs (e.g. `c4a8e3b7-5d9f-4f1a-8e3d-12345abcdef0`).\n  `requestId` returned in every response is a short request handle\n  assigned by the API gateway.\n\n\n## Webhooks\n\nSequence can deliver events to an external web server whenever certain events occur.\n\nRegister endpoints under [Settings → Webhooks in the dashboard](https://app.getsequence.io/account/webhooks).\nEvery endpoint you register will be subscribed to all supported events.\n\nYour server should respond to Sequence requests with a `2xx` status code. Requests that timed out or got a\ndifferent response code will be retried. We recommended to perform all processing asynchronously in order to\navoid timeouts.\n\n### Payloads\n\nSequence webhook event payloads include resource IDs without stateful data load.\nAfter receiving the webhook, use the included `resource.id` to call the relevant `GET` endpoint\n(e.g. `GET /transfers`) to receive the up-to-date state of the resource.\n\n### Signature verification\n\nEvery webhook request carries an `X-Sequence-Signature` header of the form\n`t=<unix-seconds>,v1=<hex>`. In order to verify the webhook was sent by Sequence, recompute\n`HMAC-SHA256(signingSecret, \"{t}.{rawRequestBody}\")` and compare it against `v1`.\nIt is recommended to reject the request if the signature doesn't match,\nor if `t` is more than 5 minutes from your clock (replay protection).\n\nNote that signing and verification should be performed against the *raw* request-body bytes,\nnot a re-serialized object.\n\nThe signing secret is shown **once** when you create the\nendpoint. Store it securely; to rotate it, delete and recreate the endpoint.\n\n### Delivery semantics\n\nDelivery is **at-least-once** with retries and exponential backoff, so you may\nreceive the same event more than once over a 24h time period. Each delivery carries a unique\n`X-Sequence-Event-Id`. You can use it to keep event handlers idempotent.\n\n### Supported events\n\n| Event | Description |\n| --- | --- |\n| [`transfer.changed`](#tag/transfers/webhook/POST/transferchanged) | A transfer is created or its status changes |\n| [`card_transaction.changed`](#tag/card-transactions/webhook/POST/card_transactionchanged) | A card purchase, refund, or payout is recorded |\n| [`external_transaction.changed`](#tag/external-transactions/webhook/POST/external_transactionchanged) | A connected-account transaction is first seen or settles (typically updated once a day) |\n"},"externalDocs":{"description":"Sequence website","url":"https://www.getsequence.io"},"servers":[{"url":"http://localhost:4000/platform/v1","description":"Local"},{"url":"https://dev.getsequence.io/api/platform/v1","description":"Dev"},{"url":"https://staging.getsequence.io/api/platform/v1","description":"Staging"},{"url":"https://api.getsequence.io/platform/v1","description":"Production"}],"tags":[{"name":"Accounts"},{"name":"Rules"},{"name":"Transfers","description":"Sequence tracks three kinds of money movement — make sure you're using the right one:\n\n- **Transfers (this section)**: money movements where a Sequence account is a party,\nsuch as ACH transfers, check deposits, and movements into, out of, or between Sequence\naccounts. Card activity is excluded. `GET /transfers`, `GET /transfers/{id}`.\n\n- **[Card transactions](#tag/card-transactions)**: card movements on Sequence-issued cards (`DEBIT_CARD`,\n`OMNI_CARD`) — purchases, refunds, and payouts. `GET /card-transactions`.\n\n- **[External transactions](#tag/external-transactions)**: movements on accounts you've connected to Sequence but that\nSequence does not manage (via Plaid/Finicity), surfaced for visibility only.\n`GET /external-transactions`.\n\nThe same money movement can appear in more than one place (e.g. a connected-account transfer\ninto a Sequence account shows up as both a transfer and an external transaction).\n"},{"name":"Card transactions","description":"Sequence tracks three kinds of money movement — make sure you're using the right one:\n\n- **Card transactions (this section)**: card movements on Sequence-issued cards\n(`DEBIT_CARD`, `OMNI_CARD`) — purchases, refunds, and payouts. `GET /card-transactions`.\n\n- **[Transfers](#tag/transfers)**: money movements where a Sequence account is a party, such as ACH\ntransfers, check deposits, and movements into, out of, or between Sequence accounts.\nCard activity is excluded. `GET /transfers`, `GET /transfers/{id}`.\n\n- **[External transactions](#tag/external-transactions)**: movements on accounts you've connected to Sequence but that\nSequence does not manage (via Plaid/Finicity), surfaced for visibility only.\n`GET /external-transactions`.\n\nThe same money movement can appear in more than one place (e.g. a connected-account transfer\ninto a Sequence account shows up as both a transfer and an external transaction).\n"},{"name":"External transactions","description":"Sequence tracks three kinds of money movement — make sure you're using the right one:\n\n- **External transactions (this section)**: movements on accounts you've connected to\nSequence but that Sequence does not manage (via Plaid/Finicity), surfaced for visibility\nonly. `GET /external-transactions`.\n\n- **[Transfers](#tag/transfers)**: money movements where a Sequence account is a party, such as ACH\ntransfers, check deposits, and movements into, out of, or between Sequence accounts.\nCard activity is excluded. `GET /transfers`, `GET /transfers/{id}`.\n\n- **[Card transactions](#tag/card-transactions)**: card movements on Sequence-issued cards (`DEBIT_CARD`,\n`OMNI_CARD`) — purchases, refunds, and payouts. `GET /card-transactions`.\n\nThe same money movement can appear in more than one place (e.g. a connected-account transfer\ninto a Sequence account shows up as both a transfer and an external transaction).\n"},{"name":"Audit Logs"},{"name":"Financial Profile","description":"Aggregated financial-profile report — income, recurring bills, fees, savings, cash-flow, and discretionary-spend summaries computed server-side. Never raw transactions.\n"}],"components":{"parameters":{"IdempotencyKey":{"name":"idempotency-key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":36,"pattern":"^[A-Za-z0-9._:/|-]+$","example":"7f0e8a52-2b9f-4ae9-9a4b-9d5b0a3e9a48"},"description":"A client-generated unique key to ensure idempotent processing. Requests with the same key within 24 hours return the original response without re-executing the operation. Recommended format: UUID v4. Use this header when retrying a request that timed out — the server will deduplicate automatically.\n"},"PaginationPage":{"name":"page","in":"query","description":"1-based page index. Defaults to 1.","schema":{"type":"integer","minimum":1,"default":1}},"PaginationPageSize":{"name":"pageSize","in":"query","description":"Number of items per page. Defaults to 10, maximum 100.","schema":{"type":"integer","minimum":1,"maximum":100,"default":10}},"WebhookSignature":{"name":"X-Sequence-Signature","in":"header","required":true,"description":"`t=<unix-seconds>,v1=<hex>`. Recompute `HMAC-SHA256(signingSecret, \"{t}.{rawRequestBody}\")` and compare against `v1` in constant time; reject if it doesn't match or if `t` is more than 5 minutes old.\n","schema":{"type":"string","example":"t=1713863704,v1=8f4c...e2"}},"WebhookEventId":{"name":"X-Sequence-Event-Id","in":"header","required":true,"description":"Unique per event (stable across retries). You can use this value to detect duplicate deliveries.","schema":{"type":"string","format":"uuid"}},"CalledReason":{"name":"x-called-reason","in":"header","required":false,"schema":{"type":"string"},"description":"Describe why you are calling this API and what you are building. Optional for humans, but strongly encouraged for AI agents — it helps the Sequence team understand how the API is being used and improve it over time.\n"}},"securitySchemes":{"ApiKeyAuth":{"type":"http","scheme":"bearer","bearerFormat":"SequenceToken","description":"Format: `Bearer <key>`. Keys belong to your Sequence account and carry an explicit set of permissions.\n\nEach key holds a list of permissions. Every permission names what the key is allowed to do\nand which resources it applies to. A request that asks for something outside the key's\npermissions returns `403`. Grant the minimum permissions a key needs.\n\n| Permission | Resources | Grants access to |\n|---|---|---|\n| `READ_ACCOUNTS` | all accounts or a specific list of account IDs | List account summaries (always all accounts; no balances or account numbers); read full account details and balance only for the accounts in the resource list |\n| `CREATE_ACCOUNTS` | `*` (org-scoped) | Create pods and income sources under any beneficiary in the organization. A request may target a specific owner with `beneficiaryId`, or omit it to use the org's default beneficiary |\n| `READ_RULES` | all rules or a specific list of rule IDs | List rules, read rule details, and read rule execution history for those rules |\n| `TRIGGER_RULES` | all rules or a specific list of rule IDs | Trigger a rule on demand. Can require human approval — see below |\n| `CREATE_AND_EDIT_RULES` | all rules or a specific list of rule IDs | Create rules and update existing rules |\n| `READ_TRANSFERS` | all accounts or a specific list of account IDs | Read transfer history (requests must filter by `accountId`) |\n| `MANUAL_TRANSFER` | one or more `{ source, target, max_amount? }` entries | Create a manual transfer between the specified source and target accounts, optionally capped at `max_amount` cents. Can require human approval — see below |\n| `READ_AUDIT_LOGS` | `*` (org-scoped) | Read the API key audit log for the organization |\n\n**Human approval.** The two money-movement permissions (`TRIGGER_RULES`, `MANUAL_TRANSFER`)\nadditionally carry `approval: { required: boolean }`, set from the \"require approval before\nexecution\" option when you create the key, defaulting to **on**. When required, the call\nsucceeds with `status: APPROVAL_PENDING` and an `approvalUrl` instead of executing, and an\nowner or co-owner approves or denies in the app. See *Human approval for money movement*\nin the overview.\n\n**MCP OAuth callers** don't hold a key. They get a built-in token whose permissions are\nderived from the member's org role; owners and co-owners receive both money-movement\npermissions with `approval.required` hardcoded to `true` and no resource or amount\nrestriction, and other roles receive the read set only. See *Connect via MCP* in the\noverview.\n\nA few read-only endpoints require **no permission** and are available to every valid key\nregardless of its scopes: `listBeneficiaries` returns the organization's beneficiaries\n(`id`, `name`, `beneficiaryType`) so a key can discover which `beneficiaryId` to pass when\ncreating accounts.\n"}},"responses":{"Unauthorized":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"UNAUTHORIZED","message":"Unauthorized"}}}}},"Forbidden":{"description":"`ACCESS_DENIED` — the credential lacks the required permission, or the requested resource is outside the permission's allowed list. Endpoints that create money movement or automations may also return `KYC_REQUIRED` when the organization has no verified beneficiary yet; read endpoints never do.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"ACCESS_DENIED","message":"API key does not have required permissions to access this resource"}}}}},"TooManyRequests":{"description":"Rate limit exceeded. The token has sent more than 100 requests in the current one-minute window. Check the `Retry-After` header for the number of seconds to wait before retrying.\n","headers":{"Retry-After":{"description":"Seconds remaining until the rate-limit window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"RATE_LIMIT_EXCEEDED","message":"Rate limit exceeded. Maximum 100 requests per minute per token."}}}}},"NotFound":{"description":"The referenced resource doesn't exist or isn't visible to this key. The `code` is entity-specific - e.g. `ACCOUNT_NOT_FOUND`, `RULE_NOT_FOUND`, `RULE_EXECUTION_NOT_FOUND`, `TRANSFER_NOT_FOUND`, `CARD_TRANSACTION_NOT_FOUND`, or `EXTERNAL_TRANSACTION_NOT_FOUND`.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"RULE_NOT_FOUND","message":"Rule does not exist or you don't have access to it"}}}}}},"schemas":{"SequenceApiAction":{"type":"string","enum":["GET_ACCOUNT","GET_ACCOUNT_BALANCE_HISTORY","LIST_ACCOUNTS","CREATE_ACCOUNT","LIST_BENEFICIARIES","LIST_TRANSFERS","GET_TRANSFER","CREATE_TRANSFER","TRIGGER_RULE","LIST_RULES","GET_RULE","LIST_RULE_EXECUTIONS","GET_RULE_EXECUTION","LIST_AUDIT_LOGS","CREATE_RULE","UPDATE_RULE","GET_FINANCIAL_PROFILE"]},"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string"},"message":{"type":"string"}}}}},"WebhookEventType":{"type":"string","description":"The event that occurred.","enum":["transfer.changed","card_transaction.changed","external_transaction.changed"]},"WebhookResourceType":{"type":"string","description":"Resource type the event is related to.","enum":["transfer","card_transaction","external_transaction"]},"WebhookEvent":{"type":"object","description":"Thin notification envelope delivered to registered webhook endpoints. Contains the event type and resource IDs only. Use `resource.id` with the matching GET endpoint to fetch the current resource.\n","required":["id","type","resource","created_at"],"properties":{"id":{"type":"string","format":"uuid","description":"Unique event ID. Mirrors the `X-Sequence-Event-Id` header. You can use this value to detect duplicate deliveries.\n"},"type":{"$ref":"#/components/schemas/WebhookEventType"},"resource":{"type":"object","required":["type","id"],"description":"The resource this event relates to.","properties":{"type":{"$ref":"#/components/schemas/WebhookResourceType"},"id":{"type":"string","format":"uuid","description":"ID to pass to the matching GET endpoint for `resource.type`."}}},"created_at":{"type":"string","format":"date-time","description":"ISO 8601 (UTC) time the event was created."}},"example":{"id":"b3f1c2a4-0000-0000-0000-000000000000","type":"transfer.changed","resource":{"type":"transfer","id":"d4e5f6a7-0000-0000-0000-000000000000"},"created_at":"2024-04-23T09:15:04Z"}},"Balance":{"type":"object","required":["balanceInCents","availableBalanceInCents","holdInCents","lastStatementBalanceInCents","lastStatementDate","nextPaymentMinimumInCents","nextPaymentDueDate","balanceLastUpdatedAt","error","interestRatePercentage","originalLoanAmountInCents"],"description":"Current balance information for the account.","properties":{"balanceInCents":{"type":["integer","null"],"description":"Current balance in cents. For `DEPOSITORY` and `pod` accounts this is the amount held. For `LIABILITY` accounts this is the outstanding balance owed (a positive number represents debt). Null when `error` is set.\n"},"availableBalanceInCents":{"type":["integer","null"],"description":"Available (spendable) balance in cents. May differ from balance when pending transactions exist."},"holdInCents":{"type":["integer","null"],"description":"Funds held and not available for spending, in cents. `balanceInCents` equals `availableBalanceInCents` plus `holdInCents`. Only reported for Sequence-managed accounts (`POD` and `INCOME_SOURCE`); null for external accounts, because no aggregation provider breaks a hold out separately.\n"},"lastStatementBalanceInCents":{"type":["integer","null"],"description":"Last statement balance in cents. Present for liability accounts."},"lastStatementDate":{"type":["string","null"],"format":"date","description":"Date of the last statement. Present for liability accounts."},"nextPaymentMinimumInCents":{"type":["integer","null"],"description":"Minimum payment due in cents. Present for liability accounts."},"nextPaymentDueDate":{"type":["string","null"],"format":"date","description":"Next payment due date. Present for liability accounts."},"balanceLastUpdatedAt":{"type":["string","null"],"format":"date-time","description":"Timestamp of the last balance refresh."},"error":{"type":["string","null"],"description":"Error code if balance could not be fetched. Null when balance data is available."},"interestRatePercentage":{"type":["number","null"],"description":"Interest rate percentage. Present for liability accounts."},"originalLoanAmountInCents":{"type":["integer","null"],"description":"Original loan amount in cents. Present for loan liability accounts."}}},"BalanceSnapshot":{"type":"object","required":["date","dateAttribution","balance","error"],"description":"An account's balance on one day. Exactly one of `balance` and `error` is set. Read `dateAttribution` before comparing entries across accounts — it says what `date` actually means, and it differs by account type.\n","properties":{"date":{"type":"string","format":"date","description":"The day this balance belongs to. What that means depends on `dateAttribution`.\n"},"dateAttribution":{"type":"string","enum":["BANK_DATE","SYNC_DATE"],"description":"What `date` represents. These are not interchangeable, and a chart mixing them without\nsaying so is misleading.\n\n- `BANK_DATE` — a settled banking day, as closed by the partner bank (`POD` and\n  `INCOME_SOURCE` accounts). The balance is final for that day.\n- `SYNC_DATE` — the day Sequence captured the balance (`EXTERNAL_ACCOUNT` accounts). No\n  provider exposes a banking day for these, so this is a capture date and the balance is\n  only the freshest value held that day. Use `balance.balanceLastUpdatedAt` to tell whether\n  it actually moved.\n"},"balance":{"oneOf":[{"$ref":"#/components/schemas/Balance"},{"type":"null"}],"description":"The balance recorded that day. Null when no snapshot exists for the date, in which case `error` explains why. Note `balance.error` is a different condition: a snapshot was taken but the provider reported a problem, so the amounts are null while the date is present.\n"},"error":{"oneOf":[{"$ref":"#/components/schemas/BalanceSnapshotError"},{"type":"null"}],"description":"Set only when no snapshot exists for this date. Null otherwise."}}},"BalanceSnapshotError":{"type":"object","required":["code","message"],"description":"Why a date in the requested range has no balance.","properties":{"code":{"type":"string","enum":["BALANCE_SNAPSHOT_MISSING"],"description":"`BALANCE_SNAPSHOT_MISSING` — no snapshot was collected for this date, typically because the daily collection job did not run or could not reach the account.\n"},"message":{"type":"string","description":"Human-readable explanation."}}},"Pagination":{"type":"object","required":["page","pageSize","hasNextPage"],"description":"Offset-based pagination metadata for list responses.","properties":{"page":{"type":"integer","minimum":1,"description":"1-based index of the page returned."},"pageSize":{"type":"integer","minimum":1,"description":"Maximum number of items per page for this response."},"hasNextPage":{"type":"boolean","description":"Whether a subsequent page of results exists. When true, increment `page` and re-fetch to retrieve the next batch."}}},"DateWindow":{"type":"object","required":["from","to","truncated"],"description":"The date range actually queried. A `from` older than the 90-day limit is clamped to 90 days ago rather than rejected; check `truncated` to know when that happened.\n","properties":{"from":{"type":"string","format":"date-time","description":"Effective start of the window queried (inclusive)."},"to":{"type":"string","format":"date-time","description":"Effective end of the window queried (inclusive)."},"truncated":{"type":"boolean","description":"`true` when `from` was clamped to 90 days ago, so older records were not included. `false` when the requested window was used unchanged.\n"}}},"PaginatedAccountsData":{"type":"object","required":["items","pagination"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AccountSummary"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}},"BeneficiaryType":{"type":"string","enum":["INDIVIDUAL","BUSINESS"],"description":"- `INDIVIDUAL` - a person (the account holder or a co-owner).\n- `BUSINESS` - a legal business entity (LLC, corporation, sole proprietorship, etc.).\n"},"Beneficiary":{"type":"object","required":["id","name","beneficiaryType"],"description":"A legal entity that can own accounts in the organization. Pass its `id` as `beneficiaryId` when creating a pod or income source to set the owning entity.\n","properties":{"id":{"type":"string","format":"uuid","description":"Beneficiary ID. Use as `beneficiaryId` on account creation."},"name":{"type":"string","description":"Display name of the beneficiary. For businesses this is the legal/business name; for individuals it is the account owner name(s).\n","example":"Acme LLC"},"beneficiaryType":{"$ref":"#/components/schemas/BeneficiaryType"}}},"PaginatedBeneficiariesData":{"type":"object","required":["items","pagination"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Beneficiary"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}},"PaginatedTransactionsData":{"type":"object","required":["items","pagination"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Transaction"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}},"Transaction":{"type":"object","required":["id","cardId","cardType","account","direction","subtype","status","amountInCents","description","createdAt","completedAt"],"description":"A settled card transaction associated with a Sequence-issued card. Covers purchases and refunds. Authorizations, holds, and declined attempts are not included.\n","properties":{"id":{"type":"string","format":"uuid","description":"Unique Sequence identifier for this transaction."},"cardId":{"type":"string","format":"uuid","description":"The Sequence card the transaction was made with."},"cardType":{"type":"string","enum":["DEBIT_CARD","OMNI_CARD"],"description":"- `DEBIT_CARD` - a card linked directly to a Sequence pod.\n- `OMNI_CARD` - a Sequence-issued card funded from multiple switching Sequence pods.\n"},"account":{"$ref":"#/components/schemas/TransferAccountRef","description":"The Sequence pod that funded the transaction or received the funds."},"direction":{"type":"string","enum":["MONEY_IN","MONEY_OUT"],"description":"- `MONEY_OUT` - funds leaving the account (purchase).\n- `MONEY_IN` - funds arriving in the account (refund or payout).\n"},"subtype":{"type":"string","enum":["PURCHASE","REFUND","PAYOUT"],"description":"The kind of card activity.\n- `PURCHASE` - an outgoing card purchase.\n- `REFUND` - an incoming refund / reverse of a purchase.\n- `PAYOUT` - an incoming push-to-card payout (treated as income).\n"},"status":{"type":"string","enum":["COMPLETE"],"description":"Current status of the transaction. Today, only settled transactions are returned, so `COMPLETE` is the only value. Additional values may be added when the API supports unsettled transactions.\n"},"amountInCents":{"type":"integer","description":"Transaction amount in cents. Always a positive integer."},"description":{"type":"string","description":"Human-readable description, typically the merchant name. May be empty when the underlying provider did not supply one.\n"},"createdAt":{"type":"string","format":"date-time","description":"When the transaction was recorded in Sequence."},"completedAt":{"type":"string","format":"date-time","description":"When the transaction settled."}}},"PaginatedTransfersData":{"type":"object","required":["items","pagination"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Transfer"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}},"ExternalTransaction":{"description":"A single transaction from a Plaid-connected external account.","type":"object","required":["id","accountId","amountInCents","direction","status","description","transactionDate","merchantName","category"],"properties":{"id":{"type":"string","format":"uuid"},"accountId":{"type":"string","format":"uuid"},"amountInCents":{"type":"integer","description":"Transaction amount in cents. Always a positive integer."},"direction":{"type":"string","enum":["MONEY_IN","MONEY_OUT"],"description":"- `MONEY_IN` - funds arriving into the account (e.g. a deposit).\n- `MONEY_OUT` - funds leaving the account (e.g. a payment or withdrawal).\n"},"status":{"type":"string","enum":["PENDING","COMPLETE"],"description":"- `PENDING` - the transaction has not yet settled.\n- `COMPLETE` - the transaction is posted/settled.\n"},"description":{"type":"string"},"transactionDate":{"type":"string","format":"date-time","description":"The date the transaction occurred."},"merchantName":{"type":["string","null"],"description":"Provider-normalized merchant name (e.g. `Starbucks` rather than the raw `description`). `null` when the provider didn't supply one, or the transaction predates this field being backfilled.\n"},"category":{"description":"Sequence's normalized spend category for this transaction (see `FinancialProfileCategoryBucketKey`) — the same 8-bucket taxonomy used by `GET /financial-profile`'s `categoryBreakdown`, regardless of whether the account is Plaid- or Finicity-connected. `null` when the transaction predates this field being backfilled.\n","oneOf":[{"$ref":"#/components/schemas/FinancialProfileCategoryBucketKey"},{"type":"null"}]}}},"PaginatedExternalTransactionsData":{"type":"object","required":["items","pagination","window"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ExternalTransaction"}},"pagination":{"$ref":"#/components/schemas/Pagination"},"window":{"$ref":"#/components/schemas/DateWindow"}}},"PaginatedRulesData":{"type":"object","required":["items","pagination"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/RuleSummary"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}},"PaginatedRuleExecutionSummariesData":{"type":"object","required":["items","pagination"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/RuleExecutionSummary"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}},"AuditLogEntry":{"type":"object","required":["id","createdAt","apiKeyId","apiKeyName","path","action","reason","requestId","outcome","errorCode"],"properties":{"id":{"type":"string","format":"uuid"},"createdAt":{"type":"string","format":"date-time"},"apiKeyId":{"type":"string","format":"uuid"},"apiKeyName":{"type":"string"},"path":{"type":"string","description":"HTTP request path, e.g. `/platform/v1/accounts`."},"action":{"oneOf":[{"$ref":"#/components/schemas/SequenceApiAction"},{"type":"null"}],"description":"Semantic action performed."},"reason":{"type":["string","null"],"description":"Caller-supplied intent for the request, forwarded via the `x-called-reason` header (e.g. the reason an MCP agent invoked the tool). `null` when the caller did not supply one."},"requestId":{"type":"string","description":"Unique identifier for the HTTP request."},"outcome":{"type":"string","enum":["SUCCESS","FAILURE"]},"errorCode":{"type":["string","null"],"description":"Sequence error code on failure, e.g. `NOT_FOUND`, `ACCESS_DENIED`."}}},"PaginatedAuditLogData":{"type":"object","required":["items","pagination","window"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AuditLogEntry"}},"pagination":{"$ref":"#/components/schemas/Pagination"},"window":{"$ref":"#/components/schemas/DateWindow"}}},"ManualTriggerDetails":{"type":"object","required":["type","amountInCents"],"description":"Details for an execution triggered via the \"Run rule now\" button in the webapp.","properties":{"type":{"type":"string","enum":["MANUAL"]},"amountInCents":{"type":["integer","null"],"description":"The amount in cents passed at trigger time, if provided."}}},"SequenceApiTriggerDetails":{"type":"object","required":["type","amountInCents"],"description":"Details for an execution triggered via Sequence API.","properties":{"type":{"type":"string","enum":["SEQUENCE_API"]},"amountInCents":{"type":["integer","null"],"description":"The amount in cents passed at trigger time, if provided."}}},"ScheduledTriggerDetails":{"type":"object","required":["type","scheduledTime"],"description":"Details for a scheduled execution.","properties":{"type":{"type":"string","enum":["SCHEDULED"]},"scheduledTime":{"type":["string","null"],"format":"date-time","description":"ISO 8601 timestamp of when the execution was scheduled to fire."}}},"OnFundsTransferredTriggerDetails":{"type":"object","required":["type","amountInCents"],"description":"Details for an execution triggered by an incoming transfer.","properties":{"type":{"type":"string","enum":["ON_FUNDS_TRANSFERRED"]},"amountInCents":{"type":["integer","null"],"description":"The amount in cents of the incoming transfer that triggered the execution."}}},"RemoteApiTriggerDetails":{"type":"object","required":["type"],"description":"Details for an execution triggered via the Remote API.","properties":{"type":{"type":"string","enum":["REMOTE_API"]}}},"TriggerDetails":{"oneOf":[{"$ref":"#/components/schemas/ManualTriggerDetails"},{"$ref":"#/components/schemas/SequenceApiTriggerDetails"},{"$ref":"#/components/schemas/ScheduledTriggerDetails"},{"$ref":"#/components/schemas/OnFundsTransferredTriggerDetails"},{"$ref":"#/components/schemas/RemoteApiTriggerDetails"}],"discriminator":{"propertyName":"type","mapping":{"MANUAL":"#/components/schemas/ManualTriggerDetails","SEQUENCE_API":"#/components/schemas/SequenceApiTriggerDetails","SCHEDULED":"#/components/schemas/ScheduledTriggerDetails","ON_FUNDS_TRANSFERRED":"#/components/schemas/OnFundsTransferredTriggerDetails","REMOTE_API":"#/components/schemas/RemoteApiTriggerDetails"}}},"RuleExecutionStatus":{"type":"string","enum":["EXECUTED","PARTIAL","IN_PROGRESS","FAILED","APPROVAL_PENDING","APPROVAL_DENIED"],"description":"- `EXECUTED` - all transfers completed successfully.\n- `PARTIAL` - some transfers succeeded and some failed.\n- `FAILED` - execution errored or all transfers failed. A `FAILED` execution can still contain\n  completed transfers: actions run sequentially against a running source balance, so earlier\n  actions may move money before a later one errors. Check `transfersCompleted` and\n  `transferIds` rather than inferring from `status` alone.\n- `IN_PROGRESS` - the rule job is still running, a retry is scheduled, or transfers have been created but have not yet settled.\n- `APPROVAL_PENDING` - execution is awaiting explicit human approval before it can run.\n- `APPROVAL_DENIED` - execution will never run: a human denied it, or it went 24 hours\n  without a decision and the approval request expired.\n"},"ExecutionMode":{"type":"string","enum":["LIVE","SIMULATION"],"description":"- `LIVE` - real money movement\n- `SIMULATION` - dry run; no money moved\n"},"RuleExecutionListMode":{"type":"string","enum":["ALL","LIVE","SIMULATION"],"default":"LIVE","description":"Filter list results by execution mode. Defaults to `LIVE`.\n- `LIVE` - real rule executions only\n- `SIMULATION` - dry-run rule simulations only (no money moved)\n- `ALL` - both real and simulation rule executions\n"},"RuleExecutionSummary":{"type":"object","required":["id","ruleId","status","executionMode","createdAt"],"description":"Lightweight rule execution representation returned by the list endpoint.","properties":{"id":{"type":"string","format":"uuid"},"ruleId":{"type":"string"},"status":{"$ref":"#/components/schemas/RuleExecutionStatus"},"executionMode":{"$ref":"#/components/schemas/ExecutionMode"},"createdAt":{"type":"string","format":"date-time"},"reasonForApproval":{"type":["string","null"],"description":"Text the requesting agent supplied to be shown to the human approver. Present when the rule execution required approval.\n"},"approvalUrl":{"type":["string","null"],"format":"uri","description":"URL a human approver opens to approve or deny the rule execution. Present only when `status` is `APPROVAL_PENDING`.\n"}}},"RuleExecution":{"description":"Full rule execution including trigger details and outcome.","allOf":[{"$ref":"#/components/schemas/RuleExecutionSummary"},{"type":"object","required":["triggerDetails","stepIndexMatched","conditionsNotMet","transfersAttempted","transfersCompleted","transfersFailed","transfersPending","transferIds","errorMessage","nextAttemptAt"],"properties":{"triggerDetails":{"$ref":"#/components/schemas/TriggerDetails"},"stepIndexMatched":{"type":["integer","null"],"description":"Zero-based index of the first step whose conditions matched. Null if no step matched (see `conditionsNotMet`).\n"},"conditionsNotMet":{"type":"boolean","description":"True when the execution ran but no step's conditions were satisfied."},"transfersAttempted":{"type":"integer","description":"Number of transfers calculated by the rule engine for the matched step. Includes transfers that were not created because their calculated amount was zero (e.g. limit cap already exhausted, or `upToEnabled` with no remaining balance). The difference between this and the sum of `transfersCompleted`, `transfersFailed`, and `transfersPending` represents transfers that were skipped without being created.\n"},"transfersCompleted":{"type":"integer","description":"Number of transfers that completed successfully."},"transfersFailed":{"type":"integer","description":"Number of transfers that failed."},"transfersPending":{"type":"integer","description":"Number of transfers still pending settlement."},"transferIds":{"type":"array","items":{"type":"string"},"description":"IDs of transfers initiated by this execution. Details available via the Transfers API."},"errorMessage":{"type":["string","null"],"description":"User-facing error message. Present when `status` is `FAILED`."},"nextAttemptAt":{"type":["string","null"],"format":"date-time","description":"When the rule job itself is scheduled to retry after an error. Null for executions that are `IN_PROGRESS` only because transfers are still pending settlement.\n"}}}]},"AccountType":{"type":"string","enum":["INCOME_SOURCE","POD","EXTERNAL_ACCOUNT"],"description":"- `POD` - a Sequence-managed account used for money routing and saving toward goals.\n- `INCOME_SOURCE` - a special pod that serves as the entry point for a user's funds into Sequence (e.g. where a paycheck lands).\n- `EXTERNAL_ACCOUNT` - an account not managed by Sequence (e.g. a bank, credit card, or investment account).\n"},"LinkedAccountSummary":{"type":"object","required":["id","name","type","description","externalAccountType","beneficiaryName","institutionName","canBeSource","canBeDestination","createdAt","updatedAt","deletedAt"],"description":"Lightweight representation of a linked account. Identical to `AccountSummary` but without a nested `linkedAccount` field to avoid circular references.","properties":{"id":{"type":"string"},"name":{"type":"string"},"type":{"$ref":"#/components/schemas/AccountType"},"description":{"type":["string","null"],"description":"User-set note or label for the account. Can be edited in the Sequence app."},"externalAccountType":{"type":["string","null"],"enum":["DEPOSITORY","INVESTMENT","LIABILITY",null],"description":"Sub-type of an `EXTERNAL_ACCOUNT`. Null for `POD` and `INCOME_SOURCE`.\n\n- `DEPOSITORY` - a standard bank account (checking, savings).\n- `INVESTMENT` - an investment account (brokerage, 401k, etc.).\n- `LIABILITY` - a debt account (credit card, student loan, mortgage, etc.).\n"},"beneficiaryName":{"type":["string","null"],"description":"Name of the account beneficiary."},"institutionName":{"type":["string","null"],"description":"Name of the financial institution. Present for `INCOME_SOURCE` and `EXTERNAL_ACCOUNT`."},"canBeSource":{"type":"boolean","description":"Whether this account can be used as a transfer source in rules."},"canBeDestination":{"type":"boolean","description":"Whether this account can be used as a transfer destination in rules."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"deletedAt":{"type":["string","null"],"format":"date-time"}}},"LinkedAccount":{"description":"Full representation of a linked account. Identical to `Account` but without a nested `linkedAccount` field to avoid circular references.","allOf":[{"$ref":"#/components/schemas/LinkedAccountSummary"},{"type":"object","required":["routingNumber","bankAccountNumber","balance","savingsTargetInCents"],"properties":{"routingNumber":{"type":["string","null"],"description":"Routing number, masked to the last 4 digits (e.g. `••••1533` for 011401533). The full value is never returned by the API. Null when the account has no routing number on file.\n"},"bankAccountNumber":{"type":["string","null"],"description":"Bank account number, masked to the last 4 digits (e.g. `••••4892` for 1111222233334892). The full value is never returned by the API. Null when the account has no account number on file.\n"},"balance":{"oneOf":[{"$ref":"#/components/schemas/Balance"},{"type":"null"}],"description":"Current balance. Null if balance data is unavailable."},"savingsTargetInCents":{"type":["integer","null"],"description":"Savings goal in cents. Only set for POD accounts. Null for all other account types or when no target has been set."}}}]},"AccountSummary":{"type":"object","required":["id","name","type","description","externalAccountType","beneficiaryName","institutionName","canBeSource","canBeDestination","linkedAccount","createdAt","updatedAt","deletedAt"],"description":"Lightweight account representation returned by list endpoints.","properties":{"id":{"type":"string"},"name":{"type":"string"},"type":{"$ref":"#/components/schemas/AccountType"},"description":{"type":["string","null"],"description":"User-set note or label for the account. Can be edited in the Sequence app."},"externalAccountType":{"type":["string","null"],"enum":["DEPOSITORY","INVESTMENT","LIABILITY",null],"description":"Sub-type of an `EXTERNAL_ACCOUNT`. Null for `POD` and `INCOME_SOURCE`.\n\n- `DEPOSITORY` - a standard bank account (checking, savings).\n- `INVESTMENT` - an investment account (brokerage, 401k, etc.).\n- `LIABILITY` - a debt account (credit card, student loan, mortgage, etc.).\n"},"beneficiaryName":{"type":["string","null"],"description":"Name of the account beneficiary."},"institutionName":{"type":["string","null"],"description":"Name of the financial institution. Present for `INCOME_SOURCE` and `EXTERNAL_ACCOUNT`."},"canBeSource":{"type":"boolean","description":"Whether this account can be used as a transfer source in rules."},"canBeDestination":{"type":"boolean","description":"Whether this account can be used as a transfer destination in rules."},"linkedAccount":{"oneOf":[{"$ref":"#/components/schemas/LinkedAccountSummary"},{"type":"null"}],"description":"The manual liability account linked to this POD. Null for all other account types or when no linked account exists."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"deletedAt":{"type":["string","null"],"format":"date-time"}}},"Account":{"description":"Full account representation including current balance and account details. Routing and bank account numbers are always masked to the last 4 digits.\n","allOf":[{"$ref":"#/components/schemas/AccountSummary"},{"type":"object","required":["routingNumber","bankAccountNumber","balance","savingsTargetInCents","linkedAccount"],"properties":{"routingNumber":{"type":["string","null"],"description":"Routing number, masked to the last 4 digits (e.g. `••••1533` for 011401533). The full value is never returned by the API. Always null for `POD` and `INCOME_SOURCE`: those accounts do have their own routing number, but it is currently only available in the Sequence app, not through this API. For an `EXTERNAL_ACCOUNT`, null when the account has no routing number on file.\n"},"bankAccountNumber":{"type":["string","null"],"description":"Bank account number, masked to the last 4 digits (e.g. `••••4892` for 1111222233334892). The full value is never returned by the API. Always null for `POD` and `INCOME_SOURCE`: those accounts do have their own account number, but it is currently only available in the Sequence app, not through this API. For an `EXTERNAL_ACCOUNT`, null when the account has no account number on file.\n"},"balance":{"oneOf":[{"$ref":"#/components/schemas/Balance"},{"type":"null"}],"description":"Current balance. Null if balance data is unavailable."},"savingsTargetInCents":{"type":["integer","null"],"description":"Savings goal in cents. Only set for POD accounts. Null for all other account types or when no target has been set."},"linkedAccount":{"oneOf":[{"$ref":"#/components/schemas/LinkedAccount"},{"type":"null"}],"description":"The manual liability account linked to this POD. Null for all other account types or when no linked account exists."}}}]},"AccountNode":{"description":"A reference to an account. Income sources, pods, and external accounts are all represented as accounts distinguished by their type.\n","type":"object","required":["id","type","name"],"properties":{"id":{"type":"string","format":"uuid"},"type":{"$ref":"#/components/schemas/AccountType"},"name":{"type":["string","null"],"description":"Account display name. Null when the name could not be resolved."}}},"TransferCap":{"description":"Caps the amount transferred by an action.","type":"object","required":["period","amountInCents"],"properties":{"period":{"type":"string","enum":["PER_TRANSFER","PER_WEEK","PER_MONTH","PER_YEAR"],"description":"- `PER_TRANSFER` - caps each individual transfer; if the calculated amount exceeds the limit it is reduced to the limit.\n- `PER_WEEK` - cumulative cap for the current week (resets every Monday). The action is skipped once the cap is reached.\n- `PER_MONTH` - cumulative cap for the current calendar month.\n- `PER_YEAR` - cumulative cap for the current calendar year.\n"},"amountInCents":{"type":"integer","minimum":0,"description":"Maximum transfer amount in cents for the given period."}}},"TriggerOnFundsTransferred":{"type":"object","required":["type","accountId"],"description":"Fires when funds arrive at the specified account.","properties":{"type":{"type":"string","enum":["ON_FUNDS_TRANSFERRED"]},"accountId":{"type":"string","format":"uuid","description":"ID of the account to monitor for incoming funds."}}},"TriggerScheduled":{"type":"object","required":["type","scheduleType","accountId"],"description":"Fires on a recurring or one-time schedule. All times are in UTC.","properties":{"type":{"type":"string","enum":["SCHEDULED"]},"scheduleType":{"type":"string","enum":["ONE_TIME","DAILY","WEEKLY","BI_WEEKLY","MONTHLY","EVERY_OTHER_WEEK"],"description":"- `ONE_TIME` - runs once at `startDate`.\n- `DAILY` - runs every day.\n- `WEEKLY` - runs every week.\n- `BI_WEEKLY` - runs on the 1st and 15th of every month (semi-monthly, twice a month).\n- `MONTHLY` - runs once a month.\n- `EVERY_OTHER_WEEK` - runs every other calendar week (fortnightly), based on even ISO week numbers.\n"},"startDate":{"type":"string","format":"date-time","description":"Schedule start time in UTC."},"accountId":{"type":["string","null"],"format":"uuid","description":"The primary source account for this rule. Required for scheduled rules. It serves as the default source for actions and as the default account for `BALANCE` fact lookups, so a `BALANCE` condition may leave `params` unset to evaluate this account.\n"}}},"TriggerManual":{"type":"object","required":["type","accountId"],"description":"Fires only when explicitly triggered via Sequence API. An optional `executeAmount` can be passed at trigger time to drive amount-derived transfer actions (`percentage`, `round_down`, `top_up`, etc.). Fixed-amount transfers always use the value configured on the rule and are not affected by `executeAmount`.\n","properties":{"type":{"type":"string","enum":["MANUAL"]},"accountId":{"type":"string","format":"uuid","description":"The primary source account for this rule. Serves as the default source for actions and as the default account for `BALANCE` fact lookups.\n"}}},"Trigger":{"oneOf":[{"$ref":"#/components/schemas/TriggerOnFundsTransferred"},{"$ref":"#/components/schemas/TriggerScheduled"},{"$ref":"#/components/schemas/TriggerManual"}],"discriminator":{"propertyName":"type","mapping":{"ON_FUNDS_TRANSFERRED":"#/components/schemas/TriggerOnFundsTransferred","SCHEDULED":"#/components/schemas/TriggerScheduled","MANUAL":"#/components/schemas/TriggerManual"}}},"CreateRuleAccountNode":{"description":"Account reference used in rule create/update requests. Same as AccountNode but without the server-computed `name` field.","type":"object","required":["id","type"],"properties":{"id":{"type":"string","format":"uuid"},"type":{"$ref":"#/components/schemas/AccountType"}}},"CreateRuleActionBase":{"type":"object","required":["type","source","destination","groupIndex"],"properties":{"type":{"type":"string"},"source":{"$ref":"#/components/schemas/CreateRuleAccountNode"},"destination":{"$ref":"#/components/schemas/CreateRuleAccountNode"},"groupIndex":{"type":"integer","description":"Groups actions within a step that are executed together as a unit. Actions sharing the same `groupIndex` also share the same `limit` cap - the cap applies to their combined transfer amount, not individually.\n"},"upToEnabled":{"type":"boolean","description":"When true, a partial transfer is created for up to the available source balance if the calculated amount exceeds it. When false, the transfer fails if funds are insufficient.\n","default":false},"limit":{"oneOf":[{"$ref":"#/components/schemas/TransferCap"},{"type":"null"}],"description":"Null when no cap is configured."},"achDescription":{"type":["string","null"],"description":"Custom ACH description for the transfer. Null when no custom description is set."},"isDirectDeposit":{"type":"boolean","description":"When true, the transfer is sent as a direct deposit - an ACH payment classified as payroll or salary. Use this when the rule is distributing income on behalf of the user (e.g. splitting a paycheck into pods).\n"}}},"CreateRuleActionFixedAmount":{"description":"Transfer a fixed amount in cents.","allOf":[{"$ref":"#/components/schemas/CreateRuleActionBase"},{"type":"object","required":["amountInCents"],"properties":{"type":{"type":"string","enum":["FIXED"]},"amountInCents":{"type":"integer","minimum":1}}}]},"CreateRuleActionPercentage":{"description":"Transfer a percentage of the incoming amount or source balance.","allOf":[{"$ref":"#/components/schemas/CreateRuleActionBase"},{"type":"object","required":["percentageValue","percentageTarget"],"properties":{"type":{"type":"string","enum":["PERCENTAGE"]},"percentageValue":{"type":"number","format":"float","minimum":0,"maximum":100},"percentageTarget":{"type":"string","enum":["INCOMING_AMOUNT","SOURCE_ACCOUNT"],"description":"- `INCOMING_AMOUNT` - percentage of the triggering transfer amount (e.g. 20% of a $5,000 paycheck).\n- `SOURCE_ACCOUNT` - percentage of the source account's current balance at execution time.\n"}}}]},"CreateRuleActionTopUp":{"description":"Transfers exactly the amount needed to bring the destination account up to a target balance. Exactly one of `amountInCents`, `nextPaymentMinimumAccount`, `currentBalanceAccount`, or `lastStatementBalanceAccount` must be non-null to define the target.\n","allOf":[{"$ref":"#/components/schemas/CreateRuleActionBase"},{"type":"object","required":["amountInCents","nextPaymentMinimumAccount","currentBalanceAccount","lastStatementBalanceAccount"],"properties":{"type":{"type":"string","enum":["TOP_UP"]},"amountInCents":{"type":["integer","null"],"minimum":0,"description":"Fixed target balance in cents. Null when a different target type is used."},"nextPaymentMinimumAccount":{"oneOf":[{"$ref":"#/components/schemas/CreateRuleAccountNode"},{"type":"null"}],"description":"Liability account whose next payment minimum amount is used as the target. Null when a different target type is used."},"currentBalanceAccount":{"oneOf":[{"$ref":"#/components/schemas/CreateRuleAccountNode"},{"type":"null"}],"description":"Account whose current balance is used as the target. Null when a different target type is used."},"lastStatementBalanceAccount":{"oneOf":[{"$ref":"#/components/schemas/CreateRuleAccountNode"},{"type":"null"}],"description":"Liability account whose last statement balance is used as the target. Null when a different target type is used."}}}]},"CreateRuleActionRoundDown":{"description":"Rounds the source account down to `amountInCents` by transferring everything above it, leaving exactly `amountInCents` behind. Transfers `sourceBalance - amountInCents`; no transfer is created when the source is already at or below `amountInCents`.\n","allOf":[{"$ref":"#/components/schemas/CreateRuleActionBase"},{"type":"object","required":["amountInCents"],"properties":{"type":{"type":"string","enum":["ROUND_DOWN"]},"amountInCents":{"type":"integer","minimum":1,"description":"The balance to leave in the source account, in cents. Everything above it is transferred - e.g. a source holding $1,730.00 with `amountInCents: 10000` transfers $1,630.00 and leaves $100.00.\n"}}}]},"CreateRuleActionNextPaymentMinimum":{"description":"Transfer the next payment minimum amount of a liability account.","allOf":[{"$ref":"#/components/schemas/CreateRuleActionBase"},{"type":"object","properties":{"type":{"type":"string","enum":["NEXT_PAYMENT_MINIMUM"]}}}]},"CreateRuleActionTotalAmountDue":{"description":"Transfer the total amount due on a liability account.","allOf":[{"$ref":"#/components/schemas/CreateRuleActionBase"},{"type":"object","properties":{"type":{"type":"string","enum":["TOTAL_AMOUNT_DUE"]}}}]},"CreateRuleActionLastStatementBalance":{"description":"Transfer the last statement balance of a liability account.","allOf":[{"$ref":"#/components/schemas/CreateRuleActionBase"},{"type":"object","properties":{"type":{"type":"string","enum":["LAST_STATEMENT_BALANCE"]}}}]},"CreateRuleActionPercentageLiabilityBalance":{"description":"Transfer a percentage of a liability account's balance.","allOf":[{"$ref":"#/components/schemas/CreateRuleActionBase"},{"type":"object","required":["percentageValue"],"properties":{"type":{"type":"string","enum":["PERCENTAGE_LIABILITY_BALANCE"]},"percentageValue":{"type":"number","format":"float","minimum":0,"maximum":100}}}]},"CreateRuleAction":{"oneOf":[{"$ref":"#/components/schemas/CreateRuleActionFixedAmount"},{"$ref":"#/components/schemas/CreateRuleActionPercentage"},{"$ref":"#/components/schemas/CreateRuleActionTopUp"},{"$ref":"#/components/schemas/CreateRuleActionRoundDown"},{"$ref":"#/components/schemas/CreateRuleActionNextPaymentMinimum"},{"$ref":"#/components/schemas/CreateRuleActionTotalAmountDue"},{"$ref":"#/components/schemas/CreateRuleActionLastStatementBalance"},{"$ref":"#/components/schemas/CreateRuleActionPercentageLiabilityBalance"}],"discriminator":{"propertyName":"type","mapping":{"FIXED":"#/components/schemas/CreateRuleActionFixedAmount","PERCENTAGE":"#/components/schemas/CreateRuleActionPercentage","TOP_UP":"#/components/schemas/CreateRuleActionTopUp","ROUND_DOWN":"#/components/schemas/CreateRuleActionRoundDown","NEXT_PAYMENT_MINIMUM":"#/components/schemas/CreateRuleActionNextPaymentMinimum","TOTAL_AMOUNT_DUE":"#/components/schemas/CreateRuleActionTotalAmountDue","LAST_STATEMENT_BALANCE":"#/components/schemas/CreateRuleActionLastStatementBalance","PERCENTAGE_LIABILITY_BALANCE":"#/components/schemas/CreateRuleActionPercentageLiabilityBalance"}}},"CreateRuleStep":{"type":"object","required":["actions"],"description":"A step in the rule. Steps are evaluated in order — the first step whose conditions pass executes its actions and the rule stops (first-match-wins). A step with no conditions acts as a catch-all fallback.\n","properties":{"actions":{"type":"array","minItems":1,"items":{"$ref":"#/components/schemas/CreateRuleAction"}},"conditions":{"oneOf":[{"$ref":"#/components/schemas/ChainableRuleCondition"},{"type":"null"}],"description":"Condition tree that must pass for this step's actions to execute. Null means always execute."}}},"CreateRuleRequest":{"type":"object","required":["trigger","steps"],"description":"Request body for creating a rule. The rule is always created in DISABLED status — activate it via the Sequence UI.","properties":{"name":{"type":["string","null"],"description":"Optional display name for the rule."},"trigger":{"$ref":"#/components/schemas/Trigger"},"steps":{"type":"array","minItems":1,"items":{"$ref":"#/components/schemas/CreateRuleStep"}}}},"UpdateRuleRequest":{"type":"object","description":"Request body for updating a rule. All fields are optional — only provided fields are updated. `trigger` and `steps` are replaced atomically when present.\n","properties":{"name":{"type":["string","null"],"description":"Display name for the rule. Pass null to clear it."},"trigger":{"$ref":"#/components/schemas/Trigger"},"steps":{"type":"array","minItems":1,"items":{"$ref":"#/components/schemas/CreateRuleStep"}}}},"RuleActionBase":{"type":"object","required":["type","source","destination","groupIndex","upToEnabled","isDirectDeposit","limit","achDescription"],"properties":{"type":{"type":"string"},"source":{"$ref":"#/components/schemas/AccountNode"},"destination":{"$ref":"#/components/schemas/AccountNode"},"groupIndex":{"type":"integer","description":"Groups actions within a step that are executed together as a unit. Actions sharing the same `groupIndex` also share the same `limit` cap - the cap applies to their combined transfer amount, not individually.\n"},"upToEnabled":{"type":"boolean","description":"When true, a partial transfer is created for up to the available source balance if the calculated amount exceeds it. When false, the transfer fails if funds are insufficient.\n","default":false},"limit":{"oneOf":[{"$ref":"#/components/schemas/TransferCap"},{"type":"null"}],"description":"Null when no cap is configured."},"achDescription":{"type":["string","null"],"description":"Custom ACH description for the transfer. Null when no custom description is set."},"isDirectDeposit":{"type":"boolean","description":"When true, the transfer is sent as a direct deposit - an ACH payment classified as payroll or salary. Use this when the rule is distributing income on behalf of the user (e.g. splitting a paycheck into pods). Some receiving accounts require a qualifying direct deposit to unlock features such as fee waivers or higher transfer limits.\n"}}},"RuleActionFixedAmount":{"description":"Transfer a fixed amount in cents.","allOf":[{"$ref":"#/components/schemas/RuleActionBase"},{"type":"object","required":["amountInCents"],"properties":{"type":{"type":"string","enum":["FIXED"]},"amountInCents":{"type":"integer","minimum":1}}}]},"RuleActionPercentage":{"description":"Transfer a percentage of the incoming amount or source balance.","allOf":[{"$ref":"#/components/schemas/RuleActionBase"},{"type":"object","required":["percentageValue","percentageTarget"],"properties":{"type":{"type":"string","enum":["PERCENTAGE"]},"percentageValue":{"type":"number","format":"float","minimum":0,"maximum":100},"percentageTarget":{"type":"string","enum":["INCOMING_AMOUNT","SOURCE_ACCOUNT"],"description":"- `INCOMING_AMOUNT` - percentage of the triggering transfer amount (e.g. 20% of a $5,000 paycheck).\n- `SOURCE_ACCOUNT` - percentage of the source account's current balance at execution time.\n"}}}]},"RuleActionTopUp":{"description":"Transfers exactly the amount needed to bring the destination account up to a target balance, accounting for any pending transfers already in flight. If the destination already meets or exceeds the target, no transfer is created. Exactly one of `amountInCents`, `nextPaymentMinimumAccount`, `currentBalanceAccount`, or `lastStatementBalanceAccount` must be set to define the target; the others are null.\n","allOf":[{"$ref":"#/components/schemas/RuleActionBase"},{"type":"object","required":["amountInCents","nextPaymentMinimumAccount","currentBalanceAccount","lastStatementBalanceAccount"],"properties":{"type":{"type":"string","enum":["TOP_UP"]},"amountInCents":{"type":["integer","null"],"minimum":0,"description":"Fixed target balance in cents. Transfers the difference between this and the current destination balance. Null when a different target type is used."},"nextPaymentMinimumAccount":{"oneOf":[{"$ref":"#/components/schemas/AccountNode"},{"type":"null"}],"description":"Liability account whose next payment minimum amount is used as the target. Null when a different target type is used."},"currentBalanceAccount":{"oneOf":[{"$ref":"#/components/schemas/AccountNode"},{"type":"null"}],"description":"Account whose current balance is used as the target. Null when a different target type is used."},"lastStatementBalanceAccount":{"oneOf":[{"$ref":"#/components/schemas/AccountNode"},{"type":"null"}],"description":"Liability account whose last statement balance is used as the target. Null when a different target type is used."}}}]},"RuleActionRoundDown":{"description":"Rounds the source account down to `amountInCents` by transferring everything above it, leaving exactly `amountInCents` behind. Transfers `sourceBalance - amountInCents`; no transfer is created when the source is already at or below `amountInCents`.\n","allOf":[{"$ref":"#/components/schemas/RuleActionBase"},{"type":"object","required":["amountInCents"],"properties":{"type":{"type":"string","enum":["ROUND_DOWN"]},"amountInCents":{"type":"integer","minimum":1,"description":"The balance to leave in the source account, in cents. Everything above it is transferred - e.g. a source holding $1,730.00 with `amountInCents: 10000` transfers $1,630.00 and leaves $100.00.\n"}}}]},"RuleActionNextPaymentMinimum":{"description":"Transfer the next payment minimum amount of a liability account.","allOf":[{"$ref":"#/components/schemas/RuleActionBase"},{"type":"object","properties":{"type":{"type":"string","enum":["NEXT_PAYMENT_MINIMUM"]}}}]},"RuleActionTotalAmountDue":{"description":"Transfer the total amount due on a liability account.","allOf":[{"$ref":"#/components/schemas/RuleActionBase"},{"type":"object","properties":{"type":{"type":"string","enum":["TOTAL_AMOUNT_DUE"]}}}]},"RuleActionLastStatementBalance":{"description":"Transfer the last statement balance of a liability account.","allOf":[{"$ref":"#/components/schemas/RuleActionBase"},{"type":"object","properties":{"type":{"type":"string","enum":["LAST_STATEMENT_BALANCE"]}}}]},"RuleActionPercentageLiabilityBalance":{"description":"Transfer a percentage of a liability account's balance.","allOf":[{"$ref":"#/components/schemas/RuleActionBase"},{"type":"object","required":["percentageValue"],"properties":{"type":{"type":"string","enum":["PERCENTAGE_LIABILITY_BALANCE"]},"percentageValue":{"type":"number","format":"float","minimum":0,"maximum":100}}}]},"RuleAction":{"oneOf":[{"$ref":"#/components/schemas/RuleActionFixedAmount"},{"$ref":"#/components/schemas/RuleActionPercentage"},{"$ref":"#/components/schemas/RuleActionTopUp"},{"$ref":"#/components/schemas/RuleActionRoundDown"},{"$ref":"#/components/schemas/RuleActionNextPaymentMinimum"},{"$ref":"#/components/schemas/RuleActionTotalAmountDue"},{"$ref":"#/components/schemas/RuleActionLastStatementBalance"},{"$ref":"#/components/schemas/RuleActionPercentageLiabilityBalance"}],"discriminator":{"propertyName":"type","mapping":{"FIXED":"#/components/schemas/RuleActionFixedAmount","PERCENTAGE":"#/components/schemas/RuleActionPercentage","TOP_UP":"#/components/schemas/RuleActionTopUp","ROUND_DOWN":"#/components/schemas/RuleActionRoundDown","NEXT_PAYMENT_MINIMUM":"#/components/schemas/RuleActionNextPaymentMinimum","TOTAL_AMOUNT_DUE":"#/components/schemas/RuleActionTotalAmountDue","LAST_STATEMENT_BALANCE":"#/components/schemas/RuleActionLastStatementBalance","PERCENTAGE_LIABILITY_BALANCE":"#/components/schemas/RuleActionPercentageLiabilityBalance"}}},"RuleConditionParams":{"type":"object","description":"Optional scope for a condition fact (e.g. check BALANCE of a specific account).","additionalProperties":false,"properties":{"accountId":{"type":"string","description":"Specifies which account to evaluate when `fact` is `BALANCE`. Defaults to the trigger account if omitted.\n"}}},"RuleConditionFact":{"type":"string","enum":["TRANSFER_AMOUNT","BALANCE","DATE"],"description":"The value being evaluated on the left side of a condition.\n\n- `TRANSFER_AMOUNT` - the amount in cents of the transfer that initiated this execution. Meaningful for ON_FUNDS_TRANSFERRED triggers and for on-demand (`MANUAL`) or API-triggered executions where an amount was explicitly provided.\n- `BALANCE` - the current available balance of an account, in cents. Specify which account via `params.accountId`; defaults to the trigger account if omitted.\n- `DATE` - the current day of the month (1–31). Use with GREATER_THAN / LESS_THAN to restrict execution to a date window.\n"},"RuleConditionValueFact":{"type":"string","enum":["TRANSFER_AMOUNT","BALANCE","DATE","LAST_DAY_OF_MONTH","NEXT_PAYMENT_MINIMUM_AMOUNT","LAST_STATEMENT_BALANCE"],"description":"The value being evaluated on the right side of a condition.\n\n- `TRANSFER_AMOUNT` - the amount in cents of the transfer that initiated this execution. Meaningful for ON_FUNDS_TRANSFERRED triggers and for on-demand (`MANUAL`) or API-triggered executions where an amount was explicitly provided.\n- `BALANCE` - the current available balance of an account, in cents. Specify which account via `params.accountId`; defaults to the trigger account if omitted.\n- `DATE` - the current day of the month (1–31). Use with GREATER_THAN / LESS_THAN to restrict execution to a date window.\n- `LAST_DAY_OF_MONTH` - the last day of the month.\n- `NEXT_PAYMENT_MINIMUM_AMOUNT` - the next payment minimum amount of a liability account.\n- `LAST_STATEMENT_BALANCE` - the last statement balance of a liability account.\n"},"RuleConditionOperator":{"type":"string","enum":["EQUALS","NOT_EQUALS","GREATER_THAN","LESS_THAN","GREATER_THAN_OR_EQUAL","LESS_THAN_OR_EQUAL"]},"RuleCondition":{"type":"object","required":["fact","operator","value","valueFact","params"],"properties":{"fact":{"$ref":"#/components/schemas/RuleConditionFact"},"operator":{"$ref":"#/components/schemas/RuleConditionOperator"},"value":{"type":["number","null"],"description":"Literal value to compare against."},"valueFact":{"oneOf":[{"$ref":"#/components/schemas/RuleConditionValueFact"},{"type":"null"}],"description":"Compare against another fact instead of a literal `value`. Use when the threshold is dynamic — e.g. `fact: BALANCE, operator: GREATER_THAN, valueFact: TRANSFER_AMOUNT` evaluates whether the account balance exceeds the transfer amount.\n"},"params":{"oneOf":[{"$ref":"#/components/schemas/RuleConditionParams"},{"type":"null"}],"description":"Scope for the condition fact. Null when no specific account override is needed."}}},"ChainableRuleCondition":{"description":"Exactly one of `condition`, `any`, or `all` must be present. `condition` is a leaf check. `any` = OR (passes if at least one child passes). `all` = AND (passes only if every child passes). Nesting is supported.\n","oneOf":[{"type":"object","required":["condition"],"additionalProperties":false,"properties":{"condition":{"$ref":"#/components/schemas/RuleCondition"}}},{"type":"object","required":["any"],"additionalProperties":false,"properties":{"any":{"type":"array","minItems":1,"items":{"$ref":"#/components/schemas/ChainableRuleCondition"},"description":"OR - passes if at least one condition in the array passes."}}},{"type":"object","required":["all"],"additionalProperties":false,"properties":{"all":{"type":"array","minItems":1,"items":{"$ref":"#/components/schemas/ChainableRuleCondition"},"description":"AND - passes only if every condition in the array passes."}}}]},"RuleStep":{"type":"object","required":["actions","conditions"],"description":"A step in the rule. Steps are evaluated in order - the first step whose conditions pass executes its actions and the rule stops (first-match-wins). A step with no conditions acts as a catch-all fallback.\n","properties":{"conditions":{"oneOf":[{"$ref":"#/components/schemas/ChainableRuleCondition"},{"type":"null"}],"description":"Condition tree that must pass for this step's actions to execute. Null means always execute."},"actions":{"type":"array","minItems":1,"items":{"$ref":"#/components/schemas/RuleAction"}}}},"Rule":{"type":"object","required":["id","name","description","status","trigger","steps","createdAt","updatedAt","deletedAt"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":["string","null"]},"description":{"type":["string","null"]},"status":{"type":"string","enum":["ENABLED","DISABLED"],"description":"- `ENABLED` - the rule is active and will execute on its trigger condition, including on-demand and API-triggered executions.\n- `DISABLED` - the rule will not execute under any circumstance.\n"},"trigger":{"$ref":"#/components/schemas/Trigger"},"steps":{"type":"array","minItems":1,"items":{"$ref":"#/components/schemas/RuleStep"}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"deletedAt":{"type":["string","null"],"format":"date-time"}}},"RuleSummary":{"type":"object","description":"Compact rule shape returned by list endpoints. Use `GET /rules/{id}` to retrieve the full rule, including `trigger` and `steps`.\n\nWhen `isSupported` is `false`, the rule's structure cannot be expressed in this version of the public API; the rule still exists in Sequence but `GET /rules/{id}` will return `INVALID_RULE`. Treat such rules as read-only metadata.\n","required":["id","name","description","status","isSupported","createdAt","updatedAt","deletedAt"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":["string","null"]},"description":{"type":["string","null"]},"status":{"type":"string","enum":["ENABLED","DISABLED"]},"isSupported":{"type":"boolean","description":"`true` when the full rule body can be returned by `GET /rules/{id}`. `false` for rules whose underlying trigger/steps shape isn't yet representable in this version of the public API.\n"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"deletedAt":{"type":["string","null"],"format":"date-time"}}},"TriggerRuleRequest":{"type":"object","properties":{"executeAmount":{"type":"integer","minimum":0,"description":"Optional amount in cents to inject as `TRANSFER_AMOUNT` for this execution. Drives amount-derived transfer actions (`percentage`, `round_down`, `top_up`, etc.) and the corresponding rule conditions. Sets the pretend source balance the actions work from, and means exactly the same thing on a live trigger as under `simulation: true` — a dry run with a given `executeAmount` previews the amounts a live trigger with that `executeAmount` would move. When omitted, the source balance is read from the actual account.\n**Does not override fixed-amount transfers**: when a rule's action is `type: \"fixed\"`, the transfer uses the amount configured by the original rule and `executeAmount` is ignored. To drive the transferred amount from the API, configure the action as a `percentage` of source balance — the source balance for manual API triggers is set to `executeAmount`.\n"},"simulation":{"type":"boolean","description":"Enables dry run rule execution mode (no money is moved). Defaults to `false`.\nWhen `true`, runs a simulation using current account balances unless\n`executeAmount`, `simulatedSourceBalance` or `simulatedIncomingFunds` is provided.\nThe rule execution and any transfers it generates are marked\n`executionMode: SIMULATION`.\nPoll the returned `executionId` via the rule-executions and transfers APIs.\n\n**The balance a dry run works from.** Two of the amount fields *replace* the\nsource balance; one *adds* to it:\n\n    base = (simulatedSourceBalance ?? executeAmount ?? realBalance)\n           + (simulatedIncomingFunds ?? 0)\n\n`simulatedIncomingFunds` adds because it models money that has **not yet landed** -\na deposit about to arrive on top of whatever the account holds now.\n`simulatedSourceBalance` and `executeAmount` instead state what the balance *is*.\n\nA live run never sums two numbers: it reads the account's real balance, which by\nthen already includes the deposit that triggered the rule. So previewing a $1,000\ndeposit into an account holding $500 means `simulatedIncomingFunds: 100000` against\nthe real balance, producing the same $1,500 base a live run reads after settlement -\nnot `simulatedSourceBalance: 150000`, which would claim the funds have already\nsettled and leave `percentage` actions with no arriving amount to work from.\n","default":false},"simulatedSourceBalance":{"type":"integer","minimum":0,"description":"Dry-run only (ignored unless `simulation: true`). Amount in cents to use as the source account's balance instead of its real balance, for both the transfer actions and any rule conditions that read the source balance. Use it to preview a rule against a balance the account does not currently hold, e.g. `\"what would this rule do if the account held $1,500?\"`. Takes precedence over the balance implied by `executeAmount`, and is added to rather than replaced by `simulatedIncomingFunds`.\n"},"simulatedIncomingFunds":{"type":"integer","minimum":0,"description":"Dry-run only (ignored unless `simulation: true`). Amount in cents to treat as funds arriving in the source account, **added on top of** its balance - `simulatedSourceBalance` when given, otherwise the real balance. This is how to preview an `ON_FUNDS_TRANSFERRED` rule: `percentage` actions compute against the arriving amount, and source-balance conditions see balance + `simulatedIncomingFunds`. It adds rather than replaces because the funds have not settled yet; a live run reads a real balance that already contains them, so it never adds. Differs from `executeAmount` and `simulatedSourceBalance`, which both replace the balance and model a manual trigger rather than a deposit.\n"},"reasonForApproval":{"type":"string","description":"Text shown to the human approver, explaining why this execution is being requested. Only used when the token's `TRIGGER_RULES` permission has `approval.required` set.\n"}}},"TransferAccountRef":{"type":"object","required":["id","name","type","isDeleted"],"description":"Lightweight account reference identifying a transfer participant.","properties":{"id":{"type":["string","null"],"description":"Null for `EXTERNAL_ENTITY` participants, which have no Sequence record."},"name":{"type":"string","description":"The account nickname. For deleted accounts (`isDeleted: true`), this is the nickname at the time of deletion. Falls back to `\"Unknown\"` only when the referenced record cannot be located at all.\n"},"type":{"type":"string","enum":["INCOME_SOURCE","POD","EXTERNAL_ACCOUNT","EXTERNAL_ENTITY"],"description":"- `POD` - a Sequence-managed account used for money routing and saving toward goals.\n- `INCOME_SOURCE` - a special pod that serves as the entry point for a user's funds into Sequence (e.g. where a paycheck lands).\n- `EXTERNAL_ACCOUNT` - an account not managed by Sequence (e.g. a bank, credit card, or investment account).\n- `EXTERNAL_ENTITY` - an unresolved external participant with no Sequence record (e.g. ATM, external ACH pull). Only `name` is available; `id` is null.\n"},"isDeleted":{"type":["boolean","null"],"description":"True if the referenced pod, income source, or external account has been deleted from Sequence since the transfer was created. Null for `EXTERNAL_ENTITY` participants, which have no Sequence record to delete.\n"}}},"Transfer":{"type":"object","required":["id","amountInCents","direction","origin","source","destination","status","executionMode","ruleId","ruleExecutionId","errorCode","createdAt","completedAt"],"description":"Represents a single money movement. Credit card and debit card transactions are excluded - this entity covers rule-triggered transfers, user-initiated transfers, incoming funds, and externally-initiated outflows.\n","properties":{"id":{"type":"string"},"amountInCents":{"type":"integer","description":"Transfer amount in cents. Always a positive integer."},"direction":{"type":"string","enum":["MONEY_IN","MONEY_OUT","INTERNAL"],"description":"The direction of the money flow.\n\n- `MONEY_IN` - funds arriving into a Sequence account from outside (direct deposit, manual pull from linked account, cashback).\n- `MONEY_OUT` - funds leaving a Sequence account to the outside (rule payment, manual transfer to external account, ATM withdrawal).\n- `INTERNAL` - funds moving between two Sequence-owned accounts (pod to pod, pod to income source).\n"},"origin":{"type":"string","enum":["DIRECT_DEPOSIT","CHECK_DEPOSIT","CASHBACK","USER_PULL","RULE","USER","EXTERNAL_PULL","UNKNOWN"],"description":"What initiated the transfer.\n\n- `MONEY_IN` origins:\n  - `DIRECT_DEPOSIT` - ACH push into a Sequence account from an external source (employer payroll, peer transfer, payout, etc.).\n  - `CHECK_DEPOSIT` - paper check deposited to a Sequence account.\n  - `CASHBACK` - reward credited by Sequence.\n  - `USER_PULL` - user manually pulled funds from a linked external account into Sequence.\n- `MONEY_OUT` origins:\n  - `RULE` - outgoing transfer triggered by an automated rule.\n  - `USER` - outgoing transfer manually initiated by the user to an external account.\n  - `EXTERNAL_PULL` - funds withdrawn externally without going through Sequence (ATM withdrawal, external ACH pull, cleared check).\n- `INTERNAL` origins:\n  - `RULE` - internal transfer between Sequence accounts triggered by a rule.\n  - `USER` - internal transfer between Sequence accounts manually initiated by the user.\n"},"source":{"oneOf":[{"$ref":"#/components/schemas/TransferAccountRef"},{"type":"null"}],"description":"The account funds moved from. Null for `MONEY_IN` transfers where the sender is external and not a tracked Sequence account (`DIRECT_DEPOSIT`, `CHECK_DEPOSIT`, `CASHBACK`).\n"},"destination":{"oneOf":[{"$ref":"#/components/schemas/TransferAccountRef"},{"type":"null"}],"description":"The account funds moved to. Null for `EXTERNAL_PULL` transfers where the recipient (ATM, merchant) is not a tracked Sequence account.\n"},"status":{"type":"string","enum":["APPROVAL_PENDING","PROCESSING","PENDING","COMPLETE","INCOMPLETE","ERROR","CANCELLED","APPROVAL_DENIED"],"description":"- `APPROVAL_PENDING` - transfer is awaiting explicit approval before it can be processed.\n- `PROCESSING` - transfer has been created and the internal job is actively running; the payment has not yet been submitted to the payment network.\n- `PENDING` - payment submitted to the payment network, awaiting settlement.\n- `COMPLETE` - settled successfully. Once a transfer reaches this status, `completedAt` is present.\n- `INCOMPLETE` - did not complete due to insufficient funds. Once a transfer reaches this status, `errorCode` is present.\n- `ERROR` - failed before or during submission — insufficient funds on a connected external source, a disconnected account, a rejected payment. Once a transfer reaches this status, `errorCode` is present and carries the reason.\n- `CANCELLED` - transfer was cancelled before settlement.\n- `APPROVAL_DENIED` - transfer will never be processed: a human denied it, or it went\n  24 hours without a decision and the approval request expired.\n"},"executionMode":{"$ref":"#/components/schemas/ExecutionMode"},"ruleId":{"type":["string","null"],"description":"The rule that triggered this transfer. Present when `origin` is `RULE`."},"ruleExecutionId":{"type":["string","null"],"format":"uuid","description":"The specific rule execution that created this transfer. Present when `origin` is `RULE`."},"errorCode":{"type":["string","null"],"description":"Machine-readable error code. Present when `status` is `ERROR` or `INCOMPLETE`. Additional codes may be returned as the system evolves. Known codes:\n\n- `INSUFFICIENT_FUNDS` - source account had insufficient funds.\n- `DISCONNECTED_ACCOUNT` - the source or destination account was disconnected.\n- `NAME_MISMATCH` - the beneficiary name did not match the account holder name.\n- `PAYMENT_FAILED` - the payment was rejected by the payment network.\n- `PAYMENT_NOT_SUPPORTED` - the account does not support this type of payment.\n- `TRANSFER_AMOUNT_LESS_THAN_ONE_DOLLAR` - transfer amount is below the $1.00 minimum.\n- `DAILY_ACH_CREDIT_LIMIT_REACHED` - daily ACH credit limit exceeded.\n- `MONTHLY_ACH_CREDIT_LIMIT_REACHED` - monthly ACH credit limit exceeded.\n- `DAILY_ACH_DEBIT_LIMIT_REACHED` - daily ACH debit limit exceeded.\n- `MONTHLY_ACH_DEBIT_LIMIT_REACHED` - monthly ACH debit limit exceeded.\n- `NULL_BALANCE` - source account balance was unavailable at execution time.\n- `ACCOUNT_NO_MINIMUM_PAYMENT_AMOUNT` - liability account has no minimum payment amount on record.\n- `ACCOUNT_NO_LAST_STATEMENT_BALANCE` - liability account has no last statement balance on record.\n- `RESOURCE_DELETED` - source or destination account was deleted before the transfer completed.\n"},"createdAt":{"type":"string","format":"date-time"},"completedAt":{"type":["string","null"],"format":"date-time","description":"Present when the transfer reached a status `COMPLETE`."},"description":{"type":["string","null"],"description":"Memo or description attached to the transfer. Null when no memo was provided."},"addenda":{"type":["string","null"],"description":"Addenda information attached to the transfer. Null when no addenda was provided."},"reasonForApproval":{"type":["string","null"],"description":"Text the requesting agent supplied to be shown to the human approver. Present when the transfer required approval.\n"},"approvalUrl":{"type":["string","null"],"format":"uri","description":"URL a human approver opens to approve or deny the transfer. Present only when `status` is `APPROVAL_PENDING`.\n"}}},"CreateTransferRequest":{"type":"object","required":["sourceAccountId","destinationAccountId","amountInCents"],"properties":{"sourceAccountId":{"type":"string","description":"ID of the account to transfer from."},"destinationAccountId":{"type":"string","description":"ID of the account to transfer to."},"amountInCents":{"type":"integer","minimum":100,"description":"Amount to transfer in cents. Minimum $1.00 (100 cents)."},"description":{"type":"string","maxLength":10,"pattern":"^[a-zA-Z0-9 ]*$","example":"Rent May","description":"Short ACH label that appears on the recipient's bank statement (NOT a freeform\nnote or memo). Hard cap: 10 characters, letters/digits/spaces only. This limit\ncomes from ACH/NACHA constraints enforced by the underlying payment provider.\n"},"simulation":{"type":"boolean","default":false,"description":"Simulates a transfer without moving actual money. The generated transfer is marked `executionMode: SIMULATION` and comes back terminal — `COMPLETE`, or `INCOMPLETE`/`ERROR` with `errorCode: INSUFFICIENT_FUNDS` when the source's last known balance can't cover the amount. See *Testing* → *Dry runs* in the introduction.\n"},"reasonForApproval":{"type":"string","description":"Text shown to the human approver, explaining why this transfer is being requested. Only used when the token's `MANUAL_TRANSFER` permission has `approval.required` set.\n"}}},"CreateAccountRequest":{"type":"object","required":["type","name"],"properties":{"type":{"type":"string","enum":["POD","INCOME_SOURCE"],"description":"Which kind of Sequence-managed account to create. Both are real bank accounts with\ntheir own routing and account numbers, so an outside deposit can be pointed at either\n(those numbers are shown in the Sequence app; this API does not return them for either\ntype). The difference is what the account is *for*:\n- `POD` - a savings/goal bucket (e.g. Vacation, Tax Reserve), usually funded by\n  transfers or rules from elsewhere in Sequence. Supports an optional\n  `savingsTargetInCents`.\n- `INCOME_SOURCE` - the entry point where outside money is meant to land (e.g. a\n  paycheck, direct deposit, or client payment); rules then distribute what arrives.\n  The only type that supports in-app payroll switching.\n"},"name":{"type":"string","description":"Display name for the account. Letters, digits, spaces and hyphens only. Must be unique among the organization's accounts of the same type.\n","example":"Tax Reserve"},"icon":{"type":["string","null"],"description":"Emoji shown for the account on the money map. Optional — a default emoji is applied when omitted or null.\n","example":"💰"},"beneficiaryId":{"type":["string","null"],"format":"uuid","description":"ID of the legal entity (beneficiary) that will own the account. When omitted or null, the organization's default beneficiary is used. The owning entity cannot be changed after creation.\n"},"savingsTargetInCents":{"type":["integer","null"],"minimum":0,"description":"Savings goal in cents. **Pods only** — supplying this with `type: INCOME_SOURCE` returns `400 INVALID_PARAMETERS`.\n"}}},"FinancialProfileCategoryBucketKey":{"type":"string","description":"Sequence's provider-agnostic 8-bucket spend taxonomy — the same value regardless of whether the underlying account is Plaid- or Finicity-connected (their own category taxonomies differ and are never surfaced directly).\n","enum":["RENT_AND_UTILITIES","FOOD_AND_DRINK","SHOPPING","TRANSPORTATION","HEALTH","SERVICES_AND_SUBSCRIPTIONS","LOAN_PAYMENTS","OTHER"]},"FinancialProfile":{"type":"object","description":"Server-side aggregated financial-profile report — income, recurring bills, fees, savings, cash-flow, and discretionary-spend summaries. Never raw transactions.\n","required":["organizationId","createdAt","windowMonths","insights"],"properties":{"organizationId":{"type":"string","format":"uuid"},"createdAt":{"type":"string","format":"date-time","description":"When this report was generated."},"windowMonths":{"type":"integer","description":"Number of trailing months of transaction history analyzed."},"insights":{"type":"object","required":["kpis","typicalMonth","moneyIn","moneyOut","recurringCharges","categoryBreakdown","vitals","opportunities","balanceAsOf","confidences"],"properties":{"kpis":{"type":"object","required":["monthsAnalyzed","accountsCount","transactionsCount"],"properties":{"monthsAnalyzed":{"type":"integer"},"accountsCount":{"type":"integer"},"transactionsCount":{"type":"integer"}}},"typicalMonth":{"type":"object","required":["domain","months"],"properties":{"domain":{"type":"string","enum":["CASHFLOW"]},"months":{"type":"array","items":{"type":"object","required":["year","month","inflowCents","outflowCents"],"properties":{"year":{"type":"integer","description":"Calendar year, e.g. 2026.","example":2026},"month":{"type":"integer","description":"Calendar month-of-year, 1-12.","minimum":1,"maximum":12,"example":7},"inflowCents":{"type":"integer","description":"Total money in for the month, in cents."},"outflowCents":{"type":"integer","description":"Total money out for the month, in cents."}}}}}},"moneyIn":{"type":"object","required":["domain","bySource"],"properties":{"domain":{"type":"string","enum":["INCOME"]},"bySource":{"type":"array","items":{"type":"object","required":["name","frequency","amountInCents","percentage"],"properties":{"name":{"type":"string"},"frequency":{"type":"string","description":"Plaid `RecurringTransactionFrequency` value (e.g. `BIWEEKLY`), or `IRREGULAR` when no matching recurring inflow stream was found.\n"},"amountInCents":{"type":"integer"},"percentage":{"type":"integer","description":"Percentage of total money in, 0-100."}}}}}},"moneyOut":{"type":"object","required":["domain","byMerchant"],"properties":{"domain":{"type":"string","enum":["CASHFLOW"]},"byMerchant":{"type":"array","items":{"type":"object","required":["name","count","avgAmountInCents","totalAmountInCents"],"properties":{"name":{"type":"string"},"count":{"type":"integer"},"avgAmountInCents":{"type":"integer"},"totalAmountInCents":{"type":"integer"}}}}}},"recurringCharges":{"type":"object","required":["domain","charges"],"properties":{"domain":{"type":"string","enum":["BILLS"]},"charges":{"type":"array","items":{"type":"object","required":["name","frequency","amountInCents","status"],"properties":{"name":{"type":"string"},"frequency":{"type":"string","description":"Plaid `RecurringTransactionFrequency` value."},"amountInCents":{"type":"integer"},"status":{"type":"string","enum":["MATURE","EARLY_DETECTION"],"description":"Plaid's confidence signal for this recurring stream — `EARLY_DETECTION` streams are lower-confidence and worth deprioritizing in cancellation suggestions.\n"}}}}}},"categoryBreakdown":{"type":"object","required":["domain","totalMonthlySpendingInCents","buckets"],"properties":{"domain":{"type":"string","enum":["DISCRETIONARY_SPEND"]},"totalMonthlySpendingInCents":{"type":"integer"},"buckets":{"type":"array","items":{"type":"object","required":["key","label","amountInCents","percentage"],"properties":{"key":{"$ref":"#/components/schemas/FinancialProfileCategoryBucketKey"},"label":{"type":"string"},"amountInCents":{"type":"integer"},"percentage":{"type":"integer"}}}}}},"vitals":{"type":"object","description":"Each field belongs to a different confidence domain -- carried right on the field's own `domain` property, matched against insights.confidences' `domain` values, rather than a separate lookup table. There's deliberately no single \"vitals\" entry in insights.confidences.\n","required":["incomeStability","savingsRate","emergencyRunway","shortTermDebt","cashFlowCushion"],"properties":{"incomeStability":{"type":"object","required":["percentage","domain"],"properties":{"percentage":{"type":"integer"},"domain":{"type":"string","enum":["INCOME"]}}},"savingsRate":{"type":"object","required":["percentage","domain"],"properties":{"percentage":{"type":"integer"},"domain":{"type":"string","enum":["SAVINGS"]}}},"emergencyRunway":{"type":"object","required":["months","domain"],"properties":{"months":{"type":"number"},"domain":{"type":"string","enum":["BALANCE"]}}},"shortTermDebt":{"type":"object","required":["percentage","domain"],"properties":{"percentage":{"type":"integer"},"domain":{"type":"string","enum":["BILLS"]}}},"cashFlowCushion":{"type":"object","required":["multiple","domain"],"properties":{"multiple":{"type":"number"},"domain":{"type":"string","enum":["CASHFLOW"]}}}}},"opportunities":{"type":"object","description":"Each field belongs to a different confidence domain -- see insights.vitals.\n","required":["feesTotal","unearnedInterestPerYear","monthlySavings","recurringMonthlyTotal","recurring","cancelTwoSubscriptions","cancelTwoAnnualSavings"],"properties":{"feesTotal":{"type":"object","required":["cents","domain"],"properties":{"cents":{"type":"integer"},"domain":{"type":"string","enum":["FEES"]}}},"unearnedInterestPerYear":{"type":"object","required":["cents","domain"],"properties":{"cents":{"type":"integer"},"domain":{"type":"string","enum":["SAVINGS"]}}},"monthlySavings":{"type":"object","required":["cents","domain"],"properties":{"cents":{"type":"integer"},"domain":{"type":"string","enum":["SAVINGS"]}}},"recurringMonthlyTotal":{"type":"object","required":["cents","domain"],"properties":{"cents":{"type":"integer"},"domain":{"type":"string","enum":["BILLS"]}}},"recurring":{"type":"object","required":["count","domain"],"properties":{"count":{"type":"integer"},"domain":{"type":"string","enum":["BILLS"]}}},"cancelTwoSubscriptions":{"type":"object","required":["value","domain"],"properties":{"value":{"type":"array","items":{"type":"string"}},"domain":{"type":"string","enum":["BILLS"]}}},"cancelTwoAnnualSavings":{"type":"object","required":["cents","domain"],"properties":{"cents":{"type":"integer"},"domain":{"type":"string","enum":["BILLS"]}}}}},"balanceAsOf":{"type":["string","null"],"format":"date-time","description":"Timestamp of the balance snapshot used for `vitals.emergencyRunway` — surfaced rather than presenting the vital as instantaneous (Plaid balances can lag ~48-72h).\n"},"confidences":{"type":"array","description":"One entry per confidence domain. `domain` matches the same uppercase values used by every `domain` field elsewhere in this payload (e.g. `vitals.incomeStability.domain`), so a client can look up a field's confidence via `confidences.find(c => c.domain === field.domain)`.\n","items":{"type":"object","required":["domain","level"],"properties":{"domain":{"type":"string","enum":["CASHFLOW","INCOME","BILLS","FEES","DISCRETIONARY_SPEND","SAVINGS","BALANCE"]},"level":{"type":"string","enum":["HIGH","MEDIUM","LOW"]}}}}}}}}}},"webhooks":{"transfer.changed":{"post":{"summary":"Transfer changed event","description":"Sent to your registered webhook endpoints when a transfer changes status. You can fetch the full transfer details using the [`GET /transfers/{id}`](#tag/transfers/GET/transfers/{id}) endpoint.\n","tags":["Transfers"],"operationId":"onTransferChanged","parameters":[{"$ref":"#/components/parameters/WebhookSignature"},{"$ref":"#/components/parameters/WebhookEventId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEvent"},"example":{"id":"b3f1c2a4-0000-0000-0000-000000000000","type":"transfer.changed","resource":{"type":"transfer","id":"d4e5f6a7-0000-0000-0000-000000000000"},"created_at":"2024-04-23T09:15:04Z"}}}},"responses":{"2XX":{"description":"Return any 2xx to acknowledge receipt. Non-2xx responses and timeouts are retried with exponential backoff.\n"}}}},"card_transaction.changed":{"post":{"summary":"Card transaction changed event","description":"Sent to your registered webhook endpoints when a card transaction changes state. You can fetch the full card transaction details using the [`GET /card-transactions/{id}`](#tag/card-transactions/GET/card-transactions/{id}) endpoint.\n","tags":["Card transactions"],"operationId":"onCardTransactionChanged","parameters":[{"$ref":"#/components/parameters/WebhookSignature"},{"$ref":"#/components/parameters/WebhookEventId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEvent"},"example":{"id":"b3f1c2a4-0000-0000-0000-000000000010","type":"card_transaction.changed","resource":{"type":"card_transaction","id":"c1a2b3d4-0000-0000-0000-000000000010"},"created_at":"2024-04-23T09:15:04Z"}}}},"responses":{"2XX":{"description":"Return any 2xx to acknowledge receipt. Non-2xx responses and timeouts are retried with exponential backoff.\n"}}}},"external_transaction.changed":{"post":{"summary":"External transaction changed event","description":"Webhook event sent to your registered endpoints when a transaction on a connected external account is first seen or settles. External transactions receive updates approximately once every 24 hours. You can fetch the full transaction details using the [`GET /external-transactions/{id}`](#tag/external-transactions/GET/external-transactions/{id}) endpoint.\n","tags":["External transactions"],"operationId":"onExternalTransactionChanged","parameters":[{"$ref":"#/components/parameters/WebhookSignature"},{"$ref":"#/components/parameters/WebhookEventId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEvent"},"example":{"id":"b3f1c2a4-0000-0000-0000-000000000020","type":"external_transaction.changed","resource":{"type":"external_transaction","id":"e5f6a7b8-0000-0000-0000-000000000020"},"created_at":"2024-04-23T09:15:04Z"}}}},"responses":{"2XX":{"description":"Return any 2xx to acknowledge receipt. Non-2xx responses and timeouts are retried with exponential backoff.\n"}}}}},"paths":{"/accounts/{id}":{"parameters":[{"name":"id","in":"path","required":true,"description":"The account ID.","schema":{"type":"string","format":"uuid"}}],"get":{"summary":"Get an account","description":"Returns the full account including account details and current balance. Routing and bank account numbers are masked to the last 4 digits; the full values are never returned. The requested account ID must be present in the token's `READ_ACCOUNTS` resources.\n","tags":["Accounts"],"operationId":"getAccount","x-required-scope":"READ_ACCOUNTS","security":[{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/CalledReason"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","requestId"],"properties":{"data":{"$ref":"#/components/schemas/Account"},"requestId":{"type":"string","description":"Unique identifier for this request."}}},"example":{"requestId":"req-5001","data":{"id":"24b62742-5761-4d19-a47f-ce94ea1b9889","name":"Amex Gold ••1234","type":"EXTERNAL_ACCOUNT","description":null,"externalAccountType":"LIABILITY","beneficiaryName":"John Smith","institutionName":"American Express","canBeSource":false,"deletedAt":null,"routingNumber":"••••0021","bankAccountNumber":"••••1234","balance":{"balanceInCents":245000,"availableBalanceInCents":null,"holdInCents":null,"lastStatementBalanceInCents":198000,"nextPaymentMinimumInCents":3500,"nextPaymentDueDate":"2024-05-15","balanceLastUpdatedAt":"2024-04-23T06:00:00Z","error":null},"savingsTargetInCents":null,"createdAt":"2024-01-20T11:00:00Z","updatedAt":"2024-04-23T06:00:00Z"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/accounts/{accountId}/transfers":{"parameters":[{"name":"accountId","in":"path","required":true,"description":"The account ID.","schema":{"type":"string","format":"uuid"}}],"get":{"summary":"List transfers by account","description":"Returns transfers for the given account, ordered by `createdAt` descending. Credit card and debit card transactions are excluded. The account ID must be present in the token's `READ_TRANSFERS` resources.\n","tags":["Accounts"],"operationId":"listAccountTransfers","x-required-scope":"READ_TRANSFERS","security":[{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/CalledReason"},{"name":"accountRole","in":"query","description":"Controls how the account ID is matched. Defaults to `either`.\n","schema":{"type":"string","enum":["source","destination","either"],"default":"either"}},{"name":"direction","in":"query","description":"Filter by direction.","schema":{"type":"string","enum":["MONEY_IN","MONEY_OUT","INTERNAL"]}},{"name":"status","in":"query","description":"Filter by status.","schema":{"type":"string","enum":["APPROVAL_PENDING","PROCESSING","PENDING","COMPLETE","INCOMPLETE","ERROR","CANCELLED","APPROVAL_DENIED"]}},{"name":"executionMode","in":"query","description":"Filter by execution mode. Defaults to `LIVE` (real transfers only). Use `SIMULATION` for dry-run transfers, or `ALL` to include both.\n","schema":{"$ref":"#/components/schemas/RuleExecutionListMode"}},{"name":"from","in":"query","description":"Return transfers created at or after this timestamp. Accepts any RFC 3339 datetime (e.g. `2026-04-19T18:19:12Z`, `2026-04-19T18:19:12.837822+00:00`).\n","schema":{"type":"string","format":"date-time","example":"2026-04-19T18:19:12.837Z"}},{"name":"to","in":"query","description":"Return transfers created at or before this timestamp. Accepts any RFC 3339 datetime (e.g. `2026-04-19T18:19:12Z`, `2026-04-19T18:19:12.837822+00:00`).\n","schema":{"type":"string","format":"date-time","example":"2026-04-19T18:19:12.837Z"}},{"$ref":"#/components/parameters/PaginationPage"},{"$ref":"#/components/parameters/PaginationPageSize"},{"name":"origin","in":"query","description":"Filter by transfer origin.","schema":{"type":"string","enum":["DIRECT_DEPOSIT","CHECK_DEPOSIT","CASHBACK","USER_PULL","RULE","USER","EXTERNAL_PULL"]}},{"name":"ruleExecutionId","in":"query","description":"Filter by rule execution ID.","schema":{"type":"string"}},{"name":"rule_execution_id","in":"query","deprecated":true,"description":"Deprecated alias for `ruleExecutionId`. Use `ruleExecutionId` instead; this name will be removed in a future release.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","requestId"],"properties":{"data":{"$ref":"#/components/schemas/PaginatedTransfersData"},"requestId":{"type":"string","description":"Unique identifier for this request."}}},"example":{"requestId":"req-5002","data":{"items":[{"id":"809e5e0b-bb0b-49b2-867a-8b44d04d9179","amountInCents":100000,"direction":"INTERNAL","origin":"RULE","status":"COMPLETE","executionMode":"LIVE","source":{"id":"c7a7f26f-2ca5-4ae5-825a-70260591247c","name":"Main Payroll","type":"INCOME_SOURCE","isDeleted":false},"destination":{"id":"c2cb3499-2491-4185-a6f5-1a3d281b875a","name":"Emergency Fund","type":"POD","isDeleted":false},"ruleId":"551ff9b6-ddf1-4110-b611-1b11044b72d4","ruleExecutionId":"4306b3e8-6e77-4c08-ab0b-bb33654af44c","errorCode":null,"createdAt":"2024-04-23T09:15:00Z","completedAt":"2024-04-23T09:15:04Z"}],"pagination":{"page":1,"pageSize":10,"hasNextPage":false}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/accounts":{"get":{"summary":"List accounts","description":"Returns a summary of the organization's accounts. Includes income sources, pods, and external accounts. Supports optional filtering by account type. Deleted accounts are excluded by default; pass `state=ALL` to include them.\n\nThis list is **not** narrowed by the key's `READ_ACCOUNTS` resource scope — it returns every account in the organization even when the key is restricted to specific account IDs. The summary only exposes non-sensitive metadata (id, name, type, beneficiary, institution, and whether the account can be a transfer source/destination); it never includes balances or account/routing numbers. Per-account scoping is enforced on `GET /accounts/{id}`, which returns the balance and the account details — with routing and bank account numbers masked to the last 4 digits — and responds `403` for accounts outside the key's `READ_ACCOUNTS` resources.\n","tags":["Accounts"],"operationId":"listAccounts","x-required-scope":"READ_ACCOUNTS","security":[{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/CalledReason"},{"name":"type","in":"query","description":"Filter by account type.","schema":{"$ref":"#/components/schemas/AccountType"}},{"name":"state","in":"query","description":"Filter by account state in Sequence. Defaults to `ACTIVE` (only non-deleted accounts). Use `ALL` to include deleted accounts as well.\n","schema":{"type":"string","enum":["ACTIVE","ALL"],"default":"ACTIVE"}},{"$ref":"#/components/parameters/PaginationPage"},{"$ref":"#/components/parameters/PaginationPageSize"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","requestId"],"properties":{"data":{"$ref":"#/components/schemas/PaginatedAccountsData"},"requestId":{"type":"string","description":"Unique identifier for this request."}}},"example":{"requestId":"req-5003","data":{"items":[{"id":"c7a7f26f-2ca5-4ae5-825a-70260591247c","name":"Chase Checking ••4567","type":"INCOME_SOURCE","description":"Main payroll account","externalAccountType":null,"beneficiaryName":"John Smith","institutionName":"Chase","canBeSource":true,"deletedAt":null,"createdAt":"2024-01-15T10:00:00Z","updatedAt":"2024-01-15T10:00:00Z"},{"id":"c2cb3499-2491-4185-a6f5-1a3d281b875a","name":"Emergency Fund","type":"POD","description":null,"externalAccountType":null,"beneficiaryName":"John Smith","institutionName":null,"canBeSource":true,"deletedAt":null,"createdAt":"2024-02-01T09:00:00Z","updatedAt":"2024-03-10T14:30:00Z"},{"id":"24b62742-5761-4d19-a47f-ce94ea1b9889","name":"Amex Gold ••1234","type":"EXTERNAL_ACCOUNT","description":null,"externalAccountType":"LIABILITY","beneficiaryName":"John Smith","institutionName":"American Express","canBeSource":false,"deletedAt":null,"createdAt":"2024-01-20T11:00:00Z","updatedAt":"2024-01-20T11:00:00Z"}],"pagination":{"page":1,"pageSize":10,"hasNextPage":false}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"post":{"summary":"Create an account","description":"Creates a Sequence-managed account — either a **pod** or an **income source** — selected by the required `type` field.\n\nBoth kinds are real bank accounts with their own routing and account numbers, so an outside deposit can be pointed at either — though those numbers are currently only readable in the Sequence app, not through this API (`routingNumber` and `bankAccountNumber` come back null for both types). The difference is intent. A `POD` is a savings/goal bucket (e.g. Vacation, Tax Reserve), usually funded by transfers or rules from elsewhere in Sequence, and may carry an optional `savingsTargetInCents`. An `INCOME_SOURCE` is the entry point where outside money is meant to land (e.g. a paycheck or client payment) — rules then distribute what arrives, and it is the only type that supports in-app payroll switching.\n\nThe new account is owned by a single legal entity (beneficiary). Provide `beneficiaryId` to choose it; when omitted the organization's default beneficiary is used. The owning entity cannot be changed after creation. The response is the full account in the same shape as `GET /accounts/{id}` (a brand-new account has a zero balance).\n","tags":["Accounts"],"operationId":"createAccount","x-required-scope":"CREATE_ACCOUNTS","security":[{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/CalledReason"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAccountRequest"},"example":{"type":"POD","name":"Tax Reserve","icon":"💰","savingsTargetInCents":500000}}}},"responses":{"201":{"description":"Account created.","content":{"application/json":{"schema":{"type":"object","required":["data","requestId"],"properties":{"data":{"$ref":"#/components/schemas/Account"},"requestId":{"type":"string","description":"Unique identifier for this request."}}}}}},"400":{"description":"Invalid request body — e.g. a duplicate account name, an invalid name/icon, an unknown `beneficiaryId`, or `savingsTargetInCents` supplied for an `INCOME_SOURCE`.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"INVALID_PARAMETERS","message":"savingsTargetInCents is only valid for pods"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"`ACCESS_DENIED` — the key lacks `CREATE_ACCOUNTS`, or the target beneficiary belongs to another organization.\n\n`KYC_REQUIRED` — the beneficiary (or the org's default beneficiary) has not completed identity verification. The user finishes verification in the Sequence app; no key change will help.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"kycRequired":{"summary":"Beneficiary is not verified","value":{"error":{"code":"KYC_REQUIRED","message":"Beneficiary has not completed identity verification"}}},"accessDenied":{"summary":"Missing permission","value":{"error":{"code":"ACCESS_DENIED","message":"API key does not have required permissions to access this resource"}}}}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/beneficiaries":{"get":{"summary":"List beneficiaries","description":"Returns the organization's beneficiaries — the legal entities (individuals and businesses) that can own accounts. Each item carries just an `id`, a display `name`, and a `beneficiaryType`. Pass a beneficiary's `id` as `beneficiaryId` when creating a pod or income source to set the owning entity; omit it there to use the organization's default beneficiary.\n\nOnly beneficiaries that have completed identity verification (and can therefore own accounts) are returned. This endpoint requires **no permission** — any valid key can call it regardless of its scopes.\n","tags":["Accounts"],"operationId":"listBeneficiaries","x-unscoped":true,"security":[{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/CalledReason"},{"$ref":"#/components/parameters/PaginationPage"},{"$ref":"#/components/parameters/PaginationPageSize"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","requestId"],"properties":{"data":{"$ref":"#/components/schemas/PaginatedBeneficiariesData"},"requestId":{"type":"string","description":"Unique identifier for this request."}}},"example":{"requestId":"req-6001","data":{"items":[{"id":"9b1c3d2e-4f5a-6b7c-8d9e-0f1a2b3c4d5e","name":"John Smith","beneficiaryType":"INDIVIDUAL"},{"id":"1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d","name":"Acme LLC","beneficiaryType":"BUSINESS"}],"pagination":{"page":1,"pageSize":10,"hasNextPage":false}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/rules/{id}/trigger":{"parameters":[{"name":"id","in":"path","required":true,"description":"The rule ID.","schema":{"type":"string","format":"uuid"}}],"post":{"summary":"Trigger a rule","description":"Triggers a rule on demand. Works for any trigger type, regardless of the rule's configured schedule or trigger condition. An optional `executeAmount` can be provided to drive amount-derived transfer actions (`percentage`, `round_down`, `top_up`, etc.) and rule conditions that reference `TRANSFER_AMOUNT`. It does NOT override fixed-amount transfers — those always use the amount configured on the rule. For dry runs, set `simulation: true`; an `executeAmount` means the same thing there as on a live trigger, so a dry run previews the amounts a live trigger would move. `simulatedSourceBalance` and `simulatedIncomingFunds` are dry-run-only overrides for previewing balances the account does not currently hold, or funds arriving on top of it. A dry run works even on a deactivated (disabled) rule, so you can preview a rule's full effect before activating it; live triggers still require the rule to be active. Returns an execution ID that can be polled via the rule-executions and transfers APIs to track the outcome. Rule ID must be present in the token's `TRIGGER_RULES` resources.\n","tags":["Rules"],"operationId":"triggerRule","x-required-scope":"TRIGGER_RULES","security":[{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/CalledReason"},{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerRuleRequest"},"example":{"simulation":true,"executeAmount":150000}}}},"responses":{"202":{"description":"Rule execution started.","content":{"application/json":{"schema":{"type":"object","required":["data","requestId"],"properties":{"data":{"type":"object","required":["executionId","status"],"properties":{"executionId":{"type":"string","format":"uuid","description":"ID of the rule execution. Use the rule-executions API to poll for status."},"status":{"$ref":"#/components/schemas/RuleExecutionStatus"},"reasonForApproval":{"type":["string","null"],"description":"Text the requesting agent supplied to be shown to the human approver. Present when the rule execution required approval.\n"},"approvalUrl":{"type":["string","null"],"format":"uri","description":"URL a human approver opens to approve or deny the rule execution. Present only when `status` is `APPROVAL_PENDING`.\n"}}},"requestId":{"type":"string","description":"Unique identifier for this request."}}},"example":{"requestId":"req-5004","data":{"executionId":"8e1f0131-0cad-450b-9273-491905731389","status":"IN_PROGRESS"}}}}},"400":{"description":"Invalid request body (e.g. `executeAmount` is not a valid amount), or the `Idempotency-Key` was previously used with a different request body (`IDEMPOTENCY_KEY_MISMATCH`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"idempotencyMismatch":{"summary":"Idempotency-Key reused with different parameters","value":{"error":{"code":"IDEMPOTENCY_KEY_MISMATCH","message":"Idempotency-Key was already used with a different request body. Use a fresh key for new operations."}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"The rule cannot be triggered. Possible error codes:\n- `RULE_DEACTIVATED` - the rule is disabled. Re-enable the rule before triggering it via the API. Only applies to live triggers; a dry run (`simulation: true`) is allowed on a disabled rule.\n- `INVALID_RULE` - the rule's trigger type is not supported by this endpoint, or the rule has been deleted.\n- `ACCESS_DENIED` - the API key does not have the required `TRIGGER_RULES` permission for this rule.\n- `KYC_REQUIRED` - the organization has not completed identity verification, so it owns no rules to trigger.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"ruleDeactivated":{"summary":"Rule is disabled","value":{"error":{"code":"RULE_DEACTIVATED","message":"This rule is deactivated and cannot be triggered using the API"}}},"invalidRule":{"summary":"Trigger type not supported","value":{"error":{"code":"INVALID_RULE","message":"This rule cannot be triggered using the API"}}},"accessDenied":{"summary":"Missing permission for this rule","value":{"error":{"code":"ACCESS_DENIED","message":"API key does not have required permissions to access this resource"}}}}}}},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"A rule execution with the same `Idempotency-Key` is currently in flight. Retry shortly.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"RULE_EXECUTION_IN_PROGRESS","message":"A rule execution with the same idempotency key is already in progress. Retry shortly."}}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/rules":{"get":{"summary":"List rules","description":"Returns a lightweight list of all rules for the organization. Supports optional filtering by source account.","tags":["Rules"],"operationId":"listRules","x-required-scope":"READ_RULES","security":[{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/CalledReason"},{"name":"sourceId","in":"query","description":"Filter rules by source account ID.","schema":{"type":"string"}},{"$ref":"#/components/parameters/PaginationPage"},{"$ref":"#/components/parameters/PaginationPageSize"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","requestId"],"properties":{"data":{"$ref":"#/components/schemas/PaginatedRulesData"},"requestId":{"type":"string","description":"Unique identifier for this request."}}},"example":{"requestId":"req-5005","data":{"items":[{"id":"551ff9b6-ddf1-4110-b611-1b11044b72d4","name":"Auto-save on deposit","description":"Saves 20% of every incoming deposit","status":"ENABLED","isSupported":true,"createdAt":"2024-03-01T10:00:00Z","updatedAt":"2024-03-15T14:30:00Z","deletedAt":null},{"id":"e6e76d0a-a854-4ab7-95f1-ea8dcca37c2b","name":"Monthly Amex payment","description":null,"status":"ENABLED","isSupported":false,"createdAt":"2024-02-10T09:00:00Z","updatedAt":"2024-02-10T09:00:00Z","deletedAt":null}],"pagination":{"page":1,"pageSize":10,"hasNextPage":false}}}}}},"400":{"description":"Invalid filter parameters.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"post":{"summary":"Create a rule","description":"Creates a new rule in DISABLED status. Activate the rule via the Sequence UI before triggering it. Requires `CREATE_AND_EDIT_RULES` permission.\n","tags":["Rules"],"operationId":"createRule","x-required-scope":"CREATE_AND_EDIT_RULES","security":[{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/CalledReason"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRuleRequest"},"example":{"name":"Auto-save on paycheck","trigger":{"type":"ON_FUNDS_TRANSFERRED","accountId":"c7a7f26f-2ca5-4ae5-825a-70260591247c"},"steps":[{"conditions":null,"actions":[{"type":"PERCENTAGE","percentageValue":20,"percentageTarget":"INCOMING_AMOUNT","source":{"id":"c7a7f26f-2ca5-4ae5-825a-70260591247c","type":"INCOME_SOURCE"},"destination":{"id":"57ee255e-b1d7-4da4-8080-edbf783b0898","type":"POD"},"groupIndex":0}]}]}}}},"responses":{"201":{"description":"Rule created successfully. The rule is DISABLED — activate it in the Sequence UI.","content":{"application/json":{"schema":{"type":"object","required":["data","requestId"],"properties":{"data":{"$ref":"#/components/schemas/Rule"},"requestId":{"type":"string","description":"Unique identifier for this request."}}}}}},"400":{"description":"Invalid request body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"The rule structure is valid but cannot be represented by this version of the API. Common causes: unsupported action type, unsupported trigger shape.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"INVALID_RULE","message":"This rule structure is not supported by the current API version"}}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/rules/{id}":{"parameters":[{"name":"id","in":"path","required":true,"description":"The rule ID.","schema":{"type":"string","format":"uuid"}}],"get":{"summary":"Get a rule","description":"Returns the full rule including all steps, conditions, and actions. The rule ID must be present in the token's `READ_RULES` resources.\n","tags":["Rules"],"operationId":"getRule","x-required-scope":"READ_RULES","security":[{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/CalledReason"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","requestId"],"properties":{"data":{"$ref":"#/components/schemas/Rule"},"requestId":{"type":"string","description":"Unique identifier for this request."}}},"example":{"requestId":"req-5006","data":{"id":"551ff9b6-ddf1-4110-b611-1b11044b72d4","name":"Auto-save on deposit","description":"Saves 20% of every incoming deposit","status":"ENABLED","trigger":{"type":"ON_FUNDS_TRANSFERRED","accountId":"c7a7f26f-2ca5-4ae5-825a-70260591247c"},"steps":[{"conditions":{"condition":{"fact":"BALANCE","operator":"GREATER_THAN","value":50000,"valueFact":null,"params":null}},"actions":[{"type":"PERCENTAGE","percentageValue":20,"percentageTarget":"INCOMING_AMOUNT","source":{"id":"c7a7f26f-2ca5-4ae5-825a-70260591247c","type":"INCOME_SOURCE","name":null},"destination":{"id":"57ee255e-b1d7-4da4-8080-edbf783b0898","type":"POD","name":null},"groupIndex":0,"upToEnabled":false,"isDirectDeposit":false,"limit":null,"achDescription":null}]},{"conditions":null,"actions":[{"type":"FIXED","amountInCents":5000,"source":{"id":"c7a7f26f-2ca5-4ae5-825a-70260591247c","type":"INCOME_SOURCE","name":null},"destination":{"id":"fae66a7b-e93b-4d24-9ee3-8f07b8970e8e","type":"POD","name":null},"groupIndex":0,"upToEnabled":true,"isDirectDeposit":false,"limit":null,"achDescription":null}]}],"createdAt":"2024-03-01T10:00:00Z","updatedAt":"2024-03-15T14:30:00Z","deletedAt":null}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"patch":{"summary":"Update a rule","description":"Updates a rule's name, trigger, or steps. All fields are optional — only provided fields are updated. `trigger` and `steps` are replaced atomically when present. The rule ID must be present in the token's `CREATE_AND_EDIT_RULES` resources.\n","tags":["Rules"],"operationId":"updateRule","x-required-scope":"CREATE_AND_EDIT_RULES","security":[{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/CalledReason"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateRuleRequest"},"example":{"name":"Updated rule name","steps":[{"conditions":null,"actions":[{"type":"PERCENTAGE","percentageValue":30,"percentageTarget":"INCOMING_AMOUNT","source":{"id":"c7a7f26f-2ca5-4ae5-825a-70260591247c","type":"INCOME_SOURCE"},"destination":{"id":"57ee255e-b1d7-4da4-8080-edbf783b0898","type":"POD"},"groupIndex":0}]}]}}}},"responses":{"200":{"description":"Rule updated successfully.","content":{"application/json":{"schema":{"type":"object","required":["data","requestId"],"properties":{"data":{"$ref":"#/components/schemas/Rule"},"requestId":{"type":"string","description":"Unique identifier for this request."}}}}}},"400":{"description":"Invalid request body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"description":"The rule structure is valid but cannot be represented by this version of the API.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/rules/{ruleId}/executions":{"get":{"summary":"List rule executions","description":"Returns rule executions for the organization, ordered by `createdAt` descending. Supports filtering by status, trigger type, execution mode, and date range. `ruleId` is required and must be present in the token's `READ_RULES` resources.\n","tags":["Rules"],"operationId":"listRuleExecutions","x-required-scope":"READ_RULES","security":[{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/CalledReason"},{"name":"ruleId","in":"path","required":true,"description":"The rule ID.","schema":{"type":"string","format":"uuid"}},{"name":"status","in":"query","description":"Filter by execution status.","schema":{"$ref":"#/components/schemas/RuleExecutionStatus"}},{"name":"triggerType","in":"query","description":"Filter by trigger type.","schema":{"type":"string","enum":["MANUAL","SEQUENCE_API","SCHEDULED","ON_FUNDS_TRANSFERRED","REMOTE_API"]}},{"name":"executionMode","in":"query","description":"Filter by execution mode. Defaults to `LIVE` (real executions only). Use `SIMULATION` for dry-run executions, or `ALL` to include both.\n","schema":{"$ref":"#/components/schemas/RuleExecutionListMode"}},{"name":"from","in":"query","description":"Return executions created at or after this timestamp. Accepts any RFC 3339 datetime (e.g. `2026-04-19T18:19:12Z`, `2026-04-19T18:19:12.837822+00:00`).\n","schema":{"type":"string","format":"date-time","example":"2026-04-19T18:19:12.837Z"}},{"name":"to","in":"query","description":"Return executions created at or before this timestamp. Accepts any RFC 3339 datetime (e.g. `2026-04-19T18:19:12Z`, `2026-04-19T18:19:12.837822+00:00`).\n","schema":{"type":"string","format":"date-time","example":"2026-04-19T18:19:12.837Z"}},{"$ref":"#/components/parameters/PaginationPage"},{"$ref":"#/components/parameters/PaginationPageSize"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","requestId"],"properties":{"data":{"$ref":"#/components/schemas/PaginatedRuleExecutionSummariesData"},"requestId":{"type":"string","description":"Unique identifier for this request."}}},"example":{"requestId":"req-5007","data":{"items":[{"id":"4306b3e8-6e77-4c08-ab0b-bb33654af44c","ruleId":"551ff9b6-ddf1-4110-b611-1b11044b72d4","status":"EXECUTED","executionMode":"LIVE","createdAt":"2024-04-23T09:15:00Z"},{"id":"4fde08bb-8f17-45ec-9d3f-a30c6ffc1351","ruleId":"551ff9b6-ddf1-4110-b611-1b11044b72d4","status":"PARTIAL","executionMode":"LIVE","createdAt":"2024-04-20T08:00:00Z"},{"id":"0d6195f3-c855-4cc0-b150-3364bf57d07d","ruleId":"5452db06-dca6-44a8-953e-3bed41f18d64","status":"FAILED","executionMode":"SIMULATION","createdAt":"2024-04-18T14:30:00Z"}],"pagination":{"page":1,"pageSize":10,"hasNextPage":false}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/rules/{ruleId}/executions/{id}":{"parameters":[{"name":"ruleId","in":"path","required":true,"description":"The rule ID.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"The rule execution ID.","schema":{"type":"string","format":"uuid"}}],"get":{"summary":"Get a rule execution","description":"Returns the full rule execution including trigger details, outcome, and transfer IDs. The execution's rule ID must be present in the token's `READ_RULES` resources.\n","tags":["Rules"],"operationId":"getRuleExecution","x-required-scope":"READ_RULES","security":[{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/CalledReason"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","requestId"],"properties":{"data":{"$ref":"#/components/schemas/RuleExecution"},"requestId":{"type":"string","description":"Unique identifier for this request."}}},"examples":{"executed":{"summary":"Successful execution","value":{"requestId":"req-5008","data":{"id":"4306b3e8-6e77-4c08-ab0b-bb33654af44c","ruleId":"551ff9b6-ddf1-4110-b611-1b11044b72d4","status":"EXECUTED","executionMode":"LIVE","createdAt":"2024-04-23T09:15:00Z","triggerDetails":{"type":"ON_FUNDS_TRANSFERRED","amountInCents":250000},"stepIndexMatched":0,"conditionsNotMet":false,"transfersAttempted":2,"transfersCompleted":2,"transfersFailed":0,"transfersPending":0,"transferIds":["809e5e0b-bb0b-49b2-867a-8b44d04d9179","32a4182a-38b5-4058-98da-4d1b3d13ab72"],"errorMessage":null,"nextAttemptAt":null}}},"no_match":{"summary":"No step conditions matched","value":{"requestId":"req-5009","data":{"id":"4fde08bb-8f17-45ec-9d3f-a30c6ffc1351","ruleId":"551ff9b6-ddf1-4110-b611-1b11044b72d4","status":"EXECUTED","executionMode":"SIMULATION","createdAt":"2024-04-20T08:00:00Z","triggerDetails":{"type":"SCHEDULED","scheduledTime":"2024-04-20T08:00:00Z"},"stepIndexMatched":null,"conditionsNotMet":true,"transfersAttempted":0,"transfersCompleted":0,"transfersFailed":0,"transfersPending":0,"transferIds":[],"errorMessage":null,"nextAttemptAt":null}}},"failed":{"summary":"Failed execution","value":{"requestId":"req-5010","data":{"id":"0d6195f3-c855-4cc0-b150-3364bf57d07d","ruleId":"5452db06-dca6-44a8-953e-3bed41f18d64","status":"FAILED","createdAt":"2024-04-18T14:30:00Z","triggerDetails":{"type":"MANUAL","amountInCents":150000},"stepIndexMatched":0,"conditionsNotMet":false,"transfersAttempted":1,"transfersCompleted":0,"transfersFailed":1,"transfersPending":0,"transferIds":["b6fa092e-834a-4e08-a7fc-20f7e5260dd5"],"errorMessage":"Insufficient funds in source account.","nextAttemptAt":null}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/transfers/{id}":{"parameters":[{"name":"id","in":"path","required":true,"description":"The transfer ID.","schema":{"type":"string","format":"uuid"}}],"get":{"summary":"Get a transfer","description":"Returns a single transfer record by ID. The transfer's source or destination account must be in the token's `READ_TRANSFERS` resources.\n","tags":["Transfers"],"operationId":"getTransfer","x-required-scope":"READ_TRANSFERS","security":[{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/CalledReason"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","requestId"],"properties":{"data":{"$ref":"#/components/schemas/Transfer"},"requestId":{"type":"string","description":"Unique identifier for this request."}}},"examples":{"internal_rule":{"summary":"Rule-triggered internal transfer (income source → pod)","value":{"requestId":"req-5012","data":{"id":"809e5e0b-bb0b-49b2-867a-8b44d04d9179","amountInCents":100000,"direction":"INTERNAL","origin":"RULE","status":"COMPLETE","executionMode":"LIVE","source":{"id":"c7a7f26f-2ca5-4ae5-825a-70260591247c","name":"Main Payroll","type":"INCOME_SOURCE","isDeleted":false},"destination":{"id":"c2cb3499-2491-4185-a6f5-1a3d281b875a","name":"Emergency Fund","type":"POD","isDeleted":false},"ruleId":"551ff9b6-ddf1-4110-b611-1b11044b72d4","ruleExecutionId":"4306b3e8-6e77-4c08-ab0b-bb33654af44c","errorCode":null,"createdAt":"2024-04-23T09:15:00Z","completedAt":"2024-04-23T09:15:04Z"}}},"money_in_direct_deposit":{"summary":"Incoming direct deposit","value":{"requestId":"req-5013","data":{"id":"ef838647-506b-4e93-979f-a2e91aead530","amountInCents":500000,"direction":"MONEY_IN","origin":"DIRECT_DEPOSIT","status":"COMPLETE","executionMode":"LIVE","source":null,"destination":{"id":"c7a7f26f-2ca5-4ae5-825a-70260591247c","name":"Main Payroll","type":"INCOME_SOURCE","isDeleted":false},"ruleId":null,"ruleExecutionId":null,"errorCode":null,"createdAt":"2024-04-23T09:00:00Z","completedAt":"2024-04-23T09:00:00Z"}}},"money_in_user_pull":{"summary":"User pulled funds from linked external account","value":{"requestId":"req-5014","data":{"id":"7f7b52b5-da88-48b6-a63b-c9bcca12d891","amountInCents":200000,"direction":"MONEY_IN","origin":"USER_PULL","status":"PENDING","executionMode":"LIVE","source":{"id":"24b62742-5761-4d19-a47f-ce94ea1b9889","name":"Chase Checking ••4567","type":"EXTERNAL_ACCOUNT","isDeleted":false},"destination":{"id":"c2cb3499-2491-4185-a6f5-1a3d281b875a","name":"Emergency Fund","type":"POD","isDeleted":false},"ruleId":null,"ruleExecutionId":null,"errorCode":null,"createdAt":"2024-04-23T11:00:00Z","completedAt":null}}},"money_out_rule":{"summary":"Rule-triggered payment to external account","value":{"requestId":"req-5015","data":{"id":"da5d3a7c-014a-4827-91a1-f4bdbe102f74","amountInCents":245000,"direction":"MONEY_OUT","origin":"RULE","status":"PENDING","executionMode":"LIVE","source":{"id":"c2cb3499-2491-4185-a6f5-1a3d281b875a","name":"Emergency Fund","type":"POD","isDeleted":false},"destination":{"id":"24b62742-5761-4d19-a47f-ce94ea1b9889","name":"Amex Gold ••1234","type":"EXTERNAL_ACCOUNT","isDeleted":false},"ruleId":"5452db06-dca6-44a8-953e-3bed41f18d64","ruleExecutionId":"0d6195f3-c855-4cc0-b150-3364bf57d07d","errorCode":null,"createdAt":"2024-04-22T14:00:00Z","completedAt":null}}},"money_out_external_pull":{"summary":"ATM withdrawal","value":{"requestId":"req-5016","data":{"id":"b6fa092e-834a-4e08-a7fc-20f7e5260dd5","amountInCents":20000,"direction":"MONEY_OUT","origin":"EXTERNAL_PULL","status":"COMPLETE","executionMode":"LIVE","source":{"id":"c2cb3499-2491-4185-a6f5-1a3d281b875a","name":"Emergency Fund","type":"POD","isDeleted":false},"destination":null,"ruleId":null,"ruleExecutionId":null,"errorCode":null,"createdAt":"2024-04-22T18:45:00Z","completedAt":"2024-04-22T18:45:00Z"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/transfers":{"get":{"summary":"List transfers","description":"Lists **transfers**: money movements where a Sequence account is a party. This covers ACH transfers, check deposits, cashback, rule- and user-initiated ACH transfers, and externally-initiated pulls into or out of Sequence accounts. Credit and debit card transactions are excluded.\n\nEach transfer includes its `amountInCents`, `direction`, `origin` (e.g. `DIRECT_DEPOSIT`, `CHECK_DEPOSIT`, `RULE`, `USER`, `EXTERNAL_PULL`), `source` and `destination` account references, `status`, `executionMode`, the associated `ruleId` / `ruleExecutionId` (when applicable), an `errorCode` for failures, and `createdAt` / `completedAt` timestamps.\n\n`direction` is relative to your Sequence accounts: `MONEY_IN` for funds entering a Sequence-managed account from outside, `MONEY_OUT` for funds leaving to an external account, and `INTERNAL` for movements between two Sequence-managed accounts.\n\nResults are ordered by `createdAt` descending and filtered to transfers where the source or destination matches any of the supplied `accountIds`. Each account ID must be present in the token's `READ_TRANSFERS` resources (or resources must be `*`).\n","tags":["Transfers"],"operationId":"listTransfers","x-required-scope":"READ_TRANSFERS","security":[{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/CalledReason"},{"name":"accountIds","in":"query","required":true,"description":"One or more account IDs to filter by. Returns transfers where the source or destination matches any of the supplied IDs. You must grant access to each of these accounts in the token's `READ_TRANSFERS` resources (or use a token with access to all accounts).\n\nAlways use bracket notation (`accountIds[]`). For multiple IDs you can also repeat the key:\n```\nGET /platform/v1/transfers?accountIds[]=uuid1\nGET /platform/v1/transfers?accountIds[]=uuid1&accountIds[]=uuid2\nGET /platform/v1/transfers?accountIds=uuid1&accountIds=uuid2\n```\n","schema":{"type":"array","items":{"type":"string","format":"uuid"},"minItems":1},"style":"form","explode":true},{"name":"direction","in":"query","description":"Filter by direction.","schema":{"type":"string","enum":["MONEY_IN","MONEY_OUT","INTERNAL"]}},{"name":"status","in":"query","description":"Filter by status.","schema":{"type":"string","enum":["APPROVAL_PENDING","PROCESSING","PENDING","COMPLETE","INCOMPLETE","ERROR","CANCELLED","APPROVAL_DENIED"]}},{"name":"executionMode","in":"query","description":"Filter by execution mode. Defaults to `LIVE` (real transfers only). Use `SIMULATION` for dry-run transfers, or `ALL` to include both.\n","schema":{"$ref":"#/components/schemas/RuleExecutionListMode"}},{"name":"from","in":"query","description":"Return transfers created at or after this timestamp. Accepts any RFC 3339 datetime (e.g. `2026-04-19T18:19:12Z`, `2026-04-19T18:19:12.837822+00:00`).\n","schema":{"type":"string","format":"date-time","example":"2026-04-19T18:19:12.837Z"}},{"name":"to","in":"query","description":"Return transfers created at or before this timestamp. Accepts any RFC 3339 datetime (e.g. `2026-04-19T18:19:12Z`, `2026-04-19T18:19:12.837822+00:00`).\n","schema":{"type":"string","format":"date-time","example":"2026-04-19T18:19:12.837Z"}},{"$ref":"#/components/parameters/PaginationPage"},{"$ref":"#/components/parameters/PaginationPageSize"},{"name":"origin","in":"query","description":"Filter by transfer origin.","schema":{"type":"string","enum":["DIRECT_DEPOSIT","CHECK_DEPOSIT","CASHBACK","USER_PULL","RULE","USER","EXTERNAL_PULL"]}},{"name":"ruleExecutionId","in":"query","description":"Filter by rule execution ID.","schema":{"type":"string"}},{"name":"rule_execution_id","in":"query","deprecated":true,"description":"Deprecated alias for `ruleExecutionId`. Use `ruleExecutionId` instead; this name will be removed in a future release.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","requestId"],"properties":{"data":{"$ref":"#/components/schemas/PaginatedTransfersData"},"requestId":{"type":"string","description":"Unique identifier for this request."}}},"example":{"requestId":"req-5010","data":{"items":[{"id":"809e5e0b-bb0b-49b2-867a-8b44d04d9179","amountInCents":100000,"direction":"INTERNAL","origin":"RULE","status":"COMPLETE","executionMode":"LIVE","source":{"id":"c7a7f26f-2ca5-4ae5-825a-70260591247c","name":"Main Payroll","type":"INCOME_SOURCE","isDeleted":false},"destination":{"id":"c2cb3499-2491-4185-a6f5-1a3d281b875a","name":"Emergency Fund","type":"POD","isDeleted":false},"ruleId":"551ff9b6-ddf1-4110-b611-1b11044b72d4","ruleExecutionId":"4306b3e8-6e77-4c08-ab0b-bb33654af44c","errorCode":null,"createdAt":"2024-04-23T09:15:00Z","completedAt":"2024-04-23T09:15:04Z"}],"pagination":{"page":1,"pageSize":10}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"post":{"summary":"Create an ACH transfer","description":"Creates an ACH transfer from a source account to a destination account. The transfer is processed asynchronously - poll `GET /transfers/{id}` to track status. Dry run mode: set `simulation: true` to test a transfer without moving actual money. The token must have a `MANUAL_TRANSFER` permission entry whose `source` matches `sourceAccountId` and `target` matches `destinationAccountId`. If `maxAmount` is set on the matching entry, the requested amount must not exceed it.\n","tags":["Transfers"],"operationId":"createTransfer","x-required-scope":"MANUAL_TRANSFER","security":[{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/CalledReason"},{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTransferRequest"},"example":{"sourceAccountId":"c2cb3499-2491-4185-a6f5-1a3d281b875a","destinationAccountId":"24b62742-5761-4d19-a47f-ce94ea1b9889","amountInCents":50000,"simulation":true}}}},"responses":{"201":{"description":"Transfer created.","content":{"application/json":{"schema":{"type":"object","required":["data","requestId"],"properties":{"data":{"$ref":"#/components/schemas/Transfer"},"requestId":{"type":"string","description":"Unique identifier for this request."}}},"example":{"requestId":"req-5011","data":{"id":"7f7b52b5-da88-48b6-a63b-c9bcca12d891","amountInCents":50000,"direction":"MONEY_OUT","origin":"USER","status":"PROCESSING","executionMode":"LIVE","source":{"id":"c2cb3499-2491-4185-a6f5-1a3d281b875a","name":"Emergency Fund","type":"POD","isDeleted":false},"destination":{"id":"24b62742-5761-4d19-a47f-ce94ea1b9889","name":"Amex Gold ••1234","type":"EXTERNAL_ACCOUNT","isDeleted":false},"ruleId":null,"ruleExecutionId":null,"errorCode":null,"createdAt":"2024-04-25T10:00:00Z","completedAt":null}}}}},"400":{"description":"Invalid request body, or the `Idempotency-Key` was previously used with a different request body (`IDEMPOTENCY_KEY_MISMATCH`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"idempotencyMismatch":{"summary":"Idempotency-Key reused with different parameters","value":{"error":{"code":"IDEMPOTENCY_KEY_MISMATCH","message":"Idempotency-Key was already used with a different request body. Use a fresh key for new operations."}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"description":"A transfer with the same `Idempotency-Key` is currently in flight. Retry shortly.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"TRANSFER_IN_PROGRESS","message":"A transfer with the same idempotency key is already in progress. Retry shortly."}}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/external-transactions":{"get":{"summary":"List external transactions","description":"Lists transactions on **external accounts**: accounts you've connected to Sequence (via Plaid/Finicity) but that Sequence does not manage. Sequence surfaces these for visibility only; it does not initiate them.\n\nEach transaction includes the account it belongs to (`accountId`), the `amountInCents` (always a positive integer), `direction` (`MONEY_IN` / `MONEY_OUT`), `status` (`PENDING` / `COMPLETE`), a `description`, and the `transactionDate`. Results are ordered by `transactionDate` descending and filtered to the supplied `accountIds`; you can further narrow by `direction`, `status`, and a `from`/`to` date range (up to 90 days back).\n\nUnlike transfers, an external transaction identifies only one account, the connected external account in `accountId`; the counterparty is not represented (there is no `source`/`destination` pair). `direction` is relative to that account: `MONEY_IN` for funds arriving into the external account, and `MONEY_OUT` for funds leaving it.\n\nThis data is sourced from the external institution and refreshes roughly every 24 hours, so recently posted transactions may not appear immediately. Each account ID must be present in the token's `READ_TRANSFERS` resources (or resources must be `*`).\n","tags":["External transactions"],"operationId":"listExternalTransactions","x-required-scope":"READ_TRANSFERS","security":[{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/CalledReason"},{"name":"accountIds","in":"query","required":true,"description":"One or more external account IDs to filter by. You must grant access to each of these accounts in the token's `READ_TRANSFERS` resources (or use a token with access to all accounts).\n\nAlways use bracket notation (`accountIds[]`). For multiple IDs you can also repeat the key:\n```\nGET /platform/v1/external-transactions?accountIds[]=uuid1\nGET /platform/v1/external-transactions?accountIds[]=uuid1&accountIds[]=uuid2\nGET /platform/v1/external-transactions?accountIds=uuid1&accountIds=uuid2\n```\n","schema":{"type":"array","items":{"type":"string","format":"uuid"},"minItems":1},"style":"form","explode":true},{"name":"direction","in":"query","description":"Filter by direction.","schema":{"type":"string","enum":["MONEY_IN","MONEY_OUT"]}},{"name":"status","in":"query","description":"Filter by status.","schema":{"type":"string","enum":["PENDING","COMPLETE"]}},{"name":"from","in":"query","description":"Return transactions with a transactionDate at or after this timestamp. Accepts any RFC 3339 datetime (e.g. `2026-04-19T18:19:12Z`, `2026-04-19T18:19:12.837822+00:00`). Defaults to 90 days ago. A `from` older than 90 days is clamped to 90 days ago (not rejected); the effective range is echoed in `data.window` with `truncated: true`.\n","schema":{"type":"string","format":"date-time","example":"2026-04-19T18:19:12.837Z"}},{"name":"to","in":"query","description":"Return transactions with a transactionDate at or before this timestamp. Accepts any RFC 3339 datetime (e.g. `2026-04-19T18:19:12Z`, `2026-04-19T18:19:12.837822+00:00`). Defaults to now.\n","schema":{"type":"string","format":"date-time","example":"2026-04-19T18:19:12.837Z"}},{"$ref":"#/components/parameters/PaginationPage"},{"$ref":"#/components/parameters/PaginationPageSize"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","requestId"],"properties":{"data":{"$ref":"#/components/schemas/PaginatedExternalTransactionsData"},"requestId":{"type":"string","description":"Unique identifier for this request."}}},"example":{"requestId":"req-6001","data":{"items":[{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","accountId":"c7a7f26f-2ca5-4ae5-825a-70260591247c","amountInCents":4200,"direction":"MONEY_OUT","status":"COMPLETE","description":"Music subscription","transactionDate":"2024-04-20T00:00:00Z"}],"pagination":{"page":1,"pageSize":10},"window":{"from":"2026-03-20T00:00:00.000Z","to":"2026-06-18T00:00:00.000Z","truncated":false}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/external-transactions/{id}":{"parameters":[{"name":"id","in":"path","required":true,"description":"The external transaction ID (the Sequence identifier, not the provider's transaction id).","schema":{"type":"string","format":"uuid"}}],"get":{"summary":"Get an external transaction","description":"Returns a single external-account transaction by its Sequence ID. The transaction's `accountId` must be present in the token's `READ_TRANSFERS` resources (or resources must be `*`).\n","tags":["External transactions"],"operationId":"getExternalTransaction","x-required-scope":"READ_TRANSFERS","security":[{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/CalledReason"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","requestId"],"properties":{"data":{"$ref":"#/components/schemas/ExternalTransaction"},"requestId":{"type":"string","description":"Unique identifier for this request."}}},"example":{"requestId":"req-6002","data":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","accountId":"c7a7f26f-2ca5-4ae5-825a-70260591247c","amountInCents":4200,"direction":"MONEY_OUT","status":"COMPLETE","description":"Music subscription","transactionDate":"2024-04-20T00:00:00Z"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/card-transactions":{"get":{"summary":"List card transactions","description":"Returns settled card transactions (purchases and refunds) for the card transactions funded from the given account (pod), ordered by `createdAt` descending. Covers both `DEBIT_CARD` and `OMNI_CARD` purchases and refunds. Authorizations, holds, and declined attempts are not included. The `accountId` of the pod must be present in the token's `READ_TRANSFERS` resources. For an omni card, the funding account of a transaction is the pod the funds were taken from.\n","tags":["Card transactions"],"operationId":"listTransactions","x-required-scope":"READ_TRANSFERS","security":[{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/CalledReason"},{"name":"accountId","in":"query","required":true,"description":"Return card transactions funded by this account (pod ID). For an omni card, that means the pod the funds were taken out of.\n","schema":{"type":"string","format":"uuid"}},{"name":"cardId","in":"query","description":"Filter to a single card. Matches `DEBIT_CARD` or `OMNI_CARD` IDs.","schema":{"type":"string","format":"uuid"}},{"name":"from","in":"query","description":"Return transactions created at or after this timestamp. Accepts any RFC 3339 datetime.\n","schema":{"type":"string","format":"date-time","example":"2026-04-19T18:19:12.837Z"}},{"name":"to","in":"query","description":"Return transactions created at or before this timestamp. Accepts any RFC 3339 datetime.\n","schema":{"type":"string","format":"date-time","example":"2026-04-19T18:19:12.837Z"}},{"$ref":"#/components/parameters/PaginationPage"},{"$ref":"#/components/parameters/PaginationPageSize"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","requestId"],"properties":{"data":{"$ref":"#/components/schemas/PaginatedTransactionsData"},"requestId":{"type":"string","description":"Unique identifier for this request."}}},"example":{"requestId":"req-6001","data":{"items":[{"id":"5fb1c2a4-7d1e-4b08-9d2c-2e5b1d6a4c12","cardId":"3d2a8b91-3f1e-4a73-9f6a-7c1d2e3b4a55","cardType":"DEBIT_CARD","account":{"id":"c2cb3499-2491-4185-a6f5-1a3d281b875a","name":"Emergency Fund","type":"POD","isDeleted":false},"direction":"MONEY_OUT","subtype":"PURCHASE","status":"COMPLETE","amountInCents":4250,"description":"BLUE BOTTLE COFFEE","createdAt":"2026-04-22T15:30:00Z","completedAt":"2026-04-22T15:30:00Z"}],"pagination":{"page":1,"pageSize":10}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/card-transactions/{id}":{"parameters":[{"name":"id","in":"path","required":true,"description":"The card transaction ID.","schema":{"type":"string","format":"uuid"}}],"get":{"summary":"Get a card transaction","description":"Returns a single settled card transaction by ID. Covers both `DEBIT_CARD` and `OMNI_CARD` purchases and refunds. The funding/receiving account (pod) must be present in the token's `READ_TRANSFERS` resources (or resources must be `*`).\n","tags":["Card transactions"],"operationId":"getCardTransaction","x-required-scope":"READ_TRANSFERS","security":[{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/CalledReason"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","requestId"],"properties":{"data":{"$ref":"#/components/schemas/Transaction"},"requestId":{"type":"string","description":"Unique identifier for this request."}}},"example":{"requestId":"req-6003","data":{"id":"5fb1c2a4-7d1e-4b08-9d2c-2e5b1d6a4c12","cardId":"3d2a8b91-3f1e-4a73-9f6a-7c1d2e3b4a55","cardType":"DEBIT_CARD","account":{"id":"c2cb3499-2491-4185-a6f5-1a3d281b875a","name":"Emergency Fund","type":"POD","isDeleted":false},"direction":"MONEY_OUT","subtype":"PURCHASE","status":"COMPLETE","amountInCents":4250,"description":"BLUE BOTTLE COFFEE","createdAt":"2026-04-22T15:30:00Z","completedAt":"2026-04-22T15:30:00Z"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/audit-logs":{"get":{"summary":"List audit log entries","description":"Returns a paginated list of API key audit log entries for the organization, ordered by `createdAt` descending. Only entries produced by API key calls are included (no dashboard or human-actor entries). Results are limited to the last 90 days.\n","tags":["Audit Logs"],"operationId":"listAuditLog","x-required-scope":"READ_AUDIT_LOGS","security":[{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/CalledReason"},{"name":"apiKeyId","in":"query","description":"Filter by API key ID.","schema":{"type":"string","format":"uuid"}},{"name":"action","in":"query","description":"Filter by action.","schema":{"type":"string","enum":["GET_ACCOUNT","GET_ACCOUNT_BALANCE_HISTORY","LIST_ACCOUNTS","LIST_BENEFICIARIES","LIST_TRANSFERS","GET_TRANSFER","CREATE_TRANSFER","TRIGGER_RULE","LIST_RULES","GET_RULE","LIST_RULE_EXECUTIONS","GET_RULE_EXECUTION"]}},{"name":"from","in":"query","description":"ISO 8601 timestamp. Defaults to 90 days ago. A `from` older than 90 days is clamped to 90 days ago (not rejected); the effective range is echoed in `data.window` with `truncated: true`.\n","schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","description":"ISO 8601 timestamp. Defaults to now.","schema":{"type":"string","format":"date-time"}},{"$ref":"#/components/parameters/PaginationPage"},{"$ref":"#/components/parameters/PaginationPageSize"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","requestId"],"properties":{"data":{"$ref":"#/components/schemas/PaginatedAuditLogData"},"requestId":{"type":"string","description":"Unique identifier for this request."}}},"example":{"requestId":"req-9001","data":{"items":[{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","createdAt":"2024-04-23T09:15:00Z","apiKeyId":"11223344-5566-7788-99aa-bbccddeeff00","apiKeyName":"Production Key","path":"/platform/v1/accounts","action":"LIST_ACCOUNTS","requestId":"req-1234","outcome":"SUCCESS","errorCode":null}],"pagination":{"page":1,"pageSize":10},"window":{"from":"2026-03-20T00:00:00.000Z","to":"2026-06-18T00:00:00.000Z","truncated":false}}}}}},"400":{"description":"Invalid parameters (e.g. `from` is not a valid datetime).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"INVALID_PARAMETERS","message":"from is not a valid date"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/financial-profile":{"get":{"summary":"Get the financial-profile report","description":"Returns the aggregated financial-profile report for the organization (income, recurring bills, fees, savings, cash-flow, discretionary spend) — computed server-side, never raw transactions.\n\nThe report is regenerated at most once per calendar month. If a fresh report already exists, it's returned immediately (`status: COMPLETED`). Otherwise generation is triggered asynchronously and this returns `status: PROCESSING` right away — poll this same endpoint again (recommended: every 15-30s) until `status` is `COMPLETED`.\n","tags":["Financial Profile"],"operationId":"getFinancialProfile","x-required-scope":"READ_FINANCIAL_PROFILE","security":[{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/CalledReason"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["status","data","requestId"],"properties":{"status":{"type":"string","enum":["COMPLETED","PROCESSING"]},"data":{"description":"Present when `status` is `COMPLETED`; `null` while `PROCESSING`.","oneOf":[{"$ref":"#/components/schemas/FinancialProfile"},{"type":"null"}]},"requestId":{"type":"string","description":"Unique identifier for this request."}}},"examples":{"completed":{"value":{"status":"COMPLETED","requestId":"req-7001","data":{"organizationId":"org_01HXYZEXAMPLE","createdAt":"2026-07-28T14:32:00Z","windowMonths":6,"insights":{"kpis":{"monthsAnalyzed":6,"accountsCount":3,"transactionsCount":412},"typicalMonth":{"domain":"CASHFLOW","months":[{"year":2026,"month":2,"inflowCents":420000,"outflowCents":310000}]},"moneyIn":{"domain":"INCOME","bySource":[{"name":"Acme Corp Payroll","frequency":"BIWEEKLY","amountInCents":245000,"percentage":58}]},"moneyOut":{"domain":"CASHFLOW","byMerchant":[{"name":"Whole Foods","count":14,"avgAmountInCents":6250,"totalAmountInCents":87500}]},"recurringCharges":{"domain":"BILLS","charges":[{"name":"Netflix","frequency":"MONTHLY","amountInCents":1549,"status":"MATURE"}]},"categoryBreakdown":{"domain":"DISCRETIONARY_SPEND","totalMonthlySpendingInCents":340000,"buckets":[{"key":"RENT_AND_UTILITIES","label":"Rent and utilities","amountInCents":195000,"percentage":57}]},"vitals":{"incomeStability":{"percentage":78,"domain":"INCOME"},"savingsRate":{"percentage":12,"domain":"SAVINGS"},"emergencyRunway":{"months":2.4,"domain":"BALANCE"},"shortTermDebt":{"percentage":18,"domain":"BILLS"},"cashFlowCushion":{"multiple":1.3,"domain":"CASHFLOW"}},"opportunities":{"feesTotal":{"cents":14500,"domain":"FEES"},"unearnedInterestPerYear":{"cents":5800,"domain":"SAVINGS"},"monthlySavings":{"cents":42000,"domain":"SAVINGS"},"recurringMonthlyTotal":{"cents":24548,"domain":"BILLS"},"recurring":{"count":8,"domain":"BILLS"},"cancelTwoSubscriptions":{"value":["Gym Membership","Spotify"],"domain":"BILLS"},"cancelTwoAnnualSavings":{"cents":18700,"domain":"BILLS"}},"balanceAsOf":"2026-07-27T05:14:00Z","confidences":[{"domain":"CASHFLOW","level":"HIGH"},{"domain":"INCOME","level":"HIGH"},{"domain":"BILLS","level":"MEDIUM"},{"domain":"FEES","level":"LOW"},{"domain":"DISCRETIONARY_SPEND","level":"MEDIUM"},{"domain":"SAVINGS","level":"HIGH"},{"domain":"BALANCE","level":"HIGH"}]}}}},"processing":{"value":{"status":"PROCESSING","requestId":"req-7002","data":null}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}}}}