openapi: 3.1.0
info:
  title: Sequence API
  version: 1.0.0
  description: |
    The Sequence API gives you programmatic control over your money flows.
    Setup, identity verification, and rule review live in the dashboard; the
    API is how your code reads account state and executes money flows.

    [![How to get started with Sequence — video walkthrough](https://i.ytimg.com/vi/tNpSjKmWSHI/maxresdefault.jpg)](https://www.youtube.com/watch?v=tNpSjKmWSHI)

    ▶ **[Watch: how to get started](https://www.youtube.com/watch?v=tNpSjKmWSHI)** — a short
    walkthrough from signup to your first API call.


    ## Setup

    Before your first API call:

    1. **Create an account** at [app.getsequence.io](https://app.getsequence.io)
       and complete identity verification (KYC for individuals, KYB for businesses).
    2. **Connect your bank accounts** via one of the supported providers.
    3. **Create rules** (optional — you can also create them via the API with the
       `CREATE_AND_EDIT_RULES` permission). A rule is a money flow that runs
       automatically — a trigger says *when* to run, optional conditions say
       *whether* to act, and actions say *what* to do (move, split, allocate).
       Rules must be enabled by a human before they can run.
    4. **Generate an API key** under Settings → API Keys. Keys belong to your
       Sequence account and carry an explicit set of permissions. You control what
       a key can do: limit it to specific actions, to specific accounts and rules,
       cap the amount it can move, or require in-app human approval for any money
       movement — see *Human approval for money movement* below.

    If you're connecting an AI assistant rather than writing code, you can skip the
    key entirely and sign in with **OAuth** over the MCP server — no credential to
    generate, copy, or store. See *Connect via MCP* below.

    Need help? Join the [Sequence Discord](https://discord.gg/kHP4AJpcyA) and
    ask in the `#api` channel, or [contact us](https://home.getsequence.io/contact)
    with any questions.


    ## Authentication

    All API requests authenticate with a Bearer token:

    ```
    Authorization: Bearer YOUR_API_KEY
    ```

    Each key carries a list of permissions. Every permission names what the
    key is allowed to do and which resources (accounts or rules) it applies
    to. A request that asks for something outside the key's permissions
    returns `403 Forbidden`. The full permissions table is in the
    Authentication panel on the right.

    Never expose API keys in client-side code or commit them to source control.
    A key whose money-movement permissions have approval switched off can move
    money unattended, so it carries the same power as your password: only hand it
    to agents and services you trust, and revoke it from **Settings → API Keys**
    the moment you think it's exposed.

    The REST API authenticates with API keys only. The MCP server additionally
    accepts **OAuth**, where permissions aren't key-managed but built in and
    derived from the signed-in member's role: full read access, creation of rules
    that land inactive, and money movement that always requires in-app human
    approval. See *Connect via MCP* below.


    ## One key per agent

    We recommend creating a **dedicated API key for each agent, automation, or
    integration** rather than reusing one broad key across everything.

    Why this matters:

    - **Revocation.** Rotating or revoking one agent's key doesn't take down every
      other automation you've wired up.
    - **Audit.** The audit log attributes each call to the key that made it. One key
      per purpose makes the log readable.
    - **Rate-limit isolation.** The 100 req/min limit is per key. A runaway agent
      can't starve your other integrations of budget if they each carry their own key.
    - **Least privilege.** Scope each key to only the accounts and rules its owner
      needs to touch.

    Suggested naming pattern: `<tool>-<purpose>`, e.g. `claude-rule-payroll`,
    `n8n-incoming-funds`, `zapier-balance-export`.


    ## Human approval for money movement

    A money-movement permission can require that a human approves each action
    before it executes. The API call still succeeds, but it registers a *proposal*:
    nothing moves until a person approves it in the Sequence app.

    Where it applies:

    - **API keys** — configured per key, per permission, when you create the key
      under **Settings → API Keys**: the "require approval before execution" option
      on `TRIGGER_RULES` and `MANUAL_TRANSFER`. It **defaults to on**. Read
      permissions have nothing to gate, so the option appears only on those two.
    - **MCP over OAuth** — always required, and not configurable. An OAuth caller's
      permissions are built in rather than key-managed, so money movement is
      approval-gated by construction (see *Connect via MCP* below).

    ### What the caller sees

    With approval required, `POST /transfers` and `POST /rules/{id}/trigger` still
    succeed, but the resource comes back awaiting a human instead of queued for
    execution:

    ```json
    {
      "data": {
        "id": "c4a8e3b7-5d9f-4f1a-8e3d-12345abcdef0",
        "status": "APPROVAL_PENDING",
        "reasonForApproval": "Vendor invoice #4471, due Friday",
        "approvalUrl": "https://app.getsequence.io/?approvalTransferId=c4a8e3b7-5d9f-4f1a-8e3d-12345abcdef0"
      },
      "requestId": "req_..."
    }
    ```

    `APPROVAL_PENDING` is a success status, not an error condition.

    `approvalUrl` opens a focused approve/deny prompt in the Sequence app.
    Sequence also notifies the organization's owner and co-owners by email and SMS
    when a request is registered, so approval doesn't depend on your application
    relaying the URL. Poll `GET /transfers/{id}` or
    `GET /rules/{ruleId}/executions/{executionId}` for the outcome:

    | Outcome | Transfer status | Rule execution status |
    |---|---|---|
    | Approved | Proceeds as normal — `PROCESSING` → `COMPLETE` | Proceeds as normal — `IN_PROGRESS` → `EXECUTED` |
    | Denied | `APPROVAL_DENIED` | `APPROVAL_DENIED` |
    | No decision within 24 hours | `APPROVAL_DENIED` | `APPROVAL_DENIED` |

    A single terminal status covers both ways an approval can fail, so
    `APPROVAL_DENIED` is the only status you need to watch for to know a request
    will never run. It doesn't distinguish a human's denial from an expiry — if you
    need that, read the approval record itself. Re-requesting means a new call with
    a fresh `idempotency-key`.

    An owner or co-owner can approve or deny; viewers cannot.

    ### The approval reason

    Both endpoints accept a `reasonForApproval` string in the request body. It's
    shown to the approver in the app and included in the email and SMS, and it's
    echoed back on the resource as `reasonForApproval`. Without it the approver
    sees only the accounts and the amount, which is usually not enough context to
    approve on.

    Dry runs are the one exception: a `simulation: true` call is never gated, since
    it moves no money and creates nothing to approve. See *Testing* below.


    ## Connect via MCP

    Sequence runs a [Model Context Protocol](https://modelcontextprotocol.io)
    server, so AI assistants can call the API directly (list accounts, create
    transfers, trigger rules, and more) without you writing any integration
    code. Every endpoint in this reference is exposed as an MCP tool
    automatically, as well as other useful tools, so the tool set stays in
    lockstep with the API.

    - **Server URL:** `https://app.getsequence.io/api/mcp`
    - **Transport:** Streamable HTTP
    - **Authentication:** OAuth *or* an API key — see below.

    ### Authentication: OAuth or API key

    **OAuth.** Point any client that supports MCP OAuth at the server URL with
    *no* credentials. It discovers Sequence's authorization server, opens a
    browser, and you sign in to Sequence and consent. There is no key to copy,
    paste, or store, and the connection is tied to your own Sequence user, so the
    audit log attributes each call to you and the MCP client that made it.

    OAuth permissions are **built in** — there's no key to scope by hand. Sequence
    mints a token whose permissions are derived from your role in the
    organization and re-derived on every request, so a role change takes effect on
    that member's next call with nothing to rotate or revoke:

    | Your role | Built-in permissions |
    |---|---|
    | 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** |
    | Viewer, or any other role | Full read access only |

    What that means in practice:

    - **Money movement is proposal-only.** `TRIGGER_RULES` and `MANUAL_TRANSFER`
      are granted with approval hardcoded on, and unlike an API key this is not
      configurable — there's no key-management surface for a built-in token. Every
      `createTransfer` or `triggerRule` an OAuth assistant issues comes back
      `APPROVAL_PENDING` and waits for a human (see *Human approval for money
      movement* above). Both are granted unrestricted as to accounts and amount,
      so approval is the only control on them.
    - **Rule writes don't execute.** `CREATE_AND_EDIT_RULES` creates rules
      inactive; a human activates them in the app.
    - **Read-only members stay read-only.** A viewer connecting over OAuth gets
      the read set and nothing else.

    Access tokens are short-lived; clients that request the advertised
    `offline_access` scope receive a refresh token, so you rarely re-consent.

    **API key.** Send the same key as the REST API, as an
    `Authorization: Bearer YOUR_API_KEY` header. A key's permissions apply
    identically over MCP, so an assistant can only do what its key allows. Unlike
    OAuth, a key can be scoped to specific accounts and rules, can carry a
    `max_amount` cap, and can execute money movement without approval if you
    explicitly turn that option off. Use a dedicated key per assistant (see *One
    key per agent* above).

    **Claude Code**: run this in your terminal — omit the header to connect over
    OAuth, or include it to use an API key:

    ```bash
    # OAuth — opens a browser to sign in
    claude mcp add --transport http sequence https://app.getsequence.io/api/mcp

    # API key
    claude mcp add --transport http sequence https://app.getsequence.io/api/mcp \
      --header "Authorization: Bearer YOUR_API_KEY"
    ```

    **Cursor and other Streamable HTTP clients**: point the client at the server
    URL (Cursor stores this in `~/.cursor/mcp.json`). Leave out the header to
    connect over OAuth — the client prompts you to sign in to Sequence:

    ```json
    {
      "mcpServers": {
        "sequence": {
          "url": "https://app.getsequence.io/api/mcp"
        }
      }
    }
    ```

    Or add the header to use an API key instead:

    ```json
    {
      "mcpServers": {
        "sequence": {
          "url": "https://app.getsequence.io/api/mcp",
          "headers": { "Authorization": "Bearer YOUR_API_KEY" }
        }
      }
    }
    ```

    **Claude Cowork**: add `https://app.getsequence.io/api/mcp` as a custom
    connector and sign in to Sequence when prompted — nothing to paste, since it
    connects over OAuth.

    The [dashboard's MCP page](https://app.getsequence.io/account/mcp) fills in
    your server name and has the full, copy-paste setup for each client.

    ### Available tools

    The tools come in two groups: one per endpoint in this reference (named after
    the operation), plus a few guided setup tools for actions you complete in the
    dashboard. Endpoint tools enforce the same permission as the endpoint, so an
    assistant can only reach what its token allows.

    The list below is the full set. **`tools/list` is filtered to the caller's
    permissions**, so an assistant sees only the tools it can actually use — a
    read-only key, or an OAuth caller who isn't an owner or co-owner, sees neither
    `createTransfer`/`triggerRule` nor `createAccount`.

    **Accounts**

    - `listAccounts`: list income sources, pods, and connected external accounts
    - `getAccount`: fetch one account with its balance and details (routing and bank account
      numbers masked to the last 4 digits)
    - `createAccount`: create a pod (savings/goal bucket) or an income source (where outside money lands)
    - `listBeneficiaries`: list the organization's beneficiaries (legal entities that own accounts)
    - `listAccountTransfers`: list transfers for a given account

    **Rules**

    - `listRules`: list rules
    - `getRule`: fetch one rule with its full steps, conditions, and actions
    - `triggerRule`: run a rule on demand (supports a dry-run simulation)
    - `listRuleExecutions`: list a rule's executions
    - `getRuleExecution`: poll one execution for status and resulting transfers

    **Transfers & transactions**

    - `createTransfer`: move money between two accounts (supports a dry-run simulation)
    - `listTransfers` / `getTransfer`: list transfers, or fetch one by id
    - `listExternalTransactions`: transactions on connected external accounts (visibility only)
    - `listTransactions`: settled card transactions
    - `listAuditLog`: audit-log entries for the organization

    **Guided setup**

    These tools don't move money; they point the assistant (and you) to the right
    place in the dashboard, since these actions are completed there.

    - `createRule`: set up an automation that moves money on a schedule or when funds arrive
    - `connectExternalAccount`: link a bank, credit card, loan, or other outside account
    - `issueCard`: issue a debit card or Omni Card
    - `addUser`: add a co-owner or a viewer (e.g. an accountant) to the account
    - `addBusinessBeneficiary`: set up a business entity so it can own accounts and cards
    - `contactSupport`: reach a human at Sequence support

    ### Example prompts

    Once connected, ask your assistant things like:

    - *"List my Bank accounts and their balances."*
    - *"Trigger the payroll rule and tell me which transfers it created."*
    - *"Move $50 from Checking to my Tax Savings pod."*

    The last two need a money-movement permission, so they require either an OAuth
    connection as an owner or co-owner, or an API key that carries one. Both
    `createTransfer` and `triggerRule` also take a dry-run flag, so you can ask for
    a preview — *"simulate it first"* — before anything real happens (see *Testing*
    below).


    ## Base URLs

    | Environment | URL |
    |---|---|
    | Production | `https://api.getsequence.io/platform/v1` |


    ## Your first request

    A quick end-to-end smoke test: list accounts, trigger a rule, then poll
    for the outcome.

    **1. List accounts.** Requires the `READ_ACCOUNTS` permission.

    ```bash
    curl https://api.getsequence.io/platform/v1/accounts \
      -H "Authorization: Bearer $SEQUENCE_API_KEY"
    ```

    **2. Trigger a rule.** Requires `TRIGGER_RULES` on the rule's ID.
    Returns `202 Accepted` with an `executionId` — execution is asynchronous.

    ```bash
    curl -X POST https://api.getsequence.io/platform/v1/rules/$RULE_ID/trigger \
      -H "Authorization: Bearer $SEQUENCE_API_KEY" \
      -H "Content-Type: application/json" \
      -H "idempotency-key: $(uuidgen)" \
      -d '{}'
    ```

    **3. Poll for outcome.** Requires `READ_RULES`.

    ```bash
    curl https://api.getsequence.io/platform/v1/rules/$RULE_ID/executions/$EXECUTION_ID \
      -H "Authorization: Bearer $SEQUENCE_API_KEY"
    ```

    **4. Review the transfers the rule produced.** Requires `READ_TRANSFERS`
    on the account. Lists transfers in or out of the given account, newest
    first — filter the result to the `ruleExecutionId` from step 3 to find
    exactly what this run moved.

    ```bash
    curl https://api.getsequence.io/platform/v1/accounts/$ACCOUNT_ID/transfers \
      -H "Authorization: Bearer $SEQUENCE_API_KEY"
    ```


    ## Testing

    There's no self-serve sandbox stocked with fake money — you build against your
    real organization and its real accounts. What you get instead are four ways to
    exercise the API, money movement included, at little or no exposure. They
    compose, and the last three are the ones that tell you how the system really
    behaves.


    ### Dry runs: `simulation: true`

    `POST /transfers` and `POST /rules/{id}/trigger` both accept `simulation: true`.
    The request runs the real code path and returns a real, readable resource, but
    nothing is ever handed to the banking rails.

    What a dry run does and doesn't check:

    - **Checked, exactly as on a live call.** The token's permission, its account and
      rule scoping, and its `max_amount` cap; that both accounts exist and can
      transact; the $1.00 minimum. A rule dry run additionally evaluates the rule's
      conditions and its per-period transfer limits for real, against **live**
      transfer history — so a preview reflects the limit budget the rule has actually
      spent.
    - **Available funds are checked, against the last known balance.** A dry run of an
      amount the source can't cover comes back terminal with
      `errorCode: INSUFFICIENT_FUNDS`, on the same status a live transfer from that
      source would reach: `INCOMPLETE` for a pod or income source, `ERROR` for a
      connected external account. The balance is whatever we last recorded, not a fresh
      read — a dry run never asks the institution to re-poll — so a deposit that landed
      seconds ago may not be reflected yet. Sources the live call doesn't check either
      aren't gated here: a manual account, or a connected account we hold no balance
      for, still previews as `COMPLETE`. A rule dry run gates on balance the same way,
      against whichever base the simulated-balance fields below produce.

    Dry runs are **never approval-gated** — not on a key that requires approval, not
    over OAuth (see *Human approval for money movement* above). There is nothing to
    approve, so the result comes back directly.

    **A simulated transfer** returns on the normal `Transfer` shape, already
    terminal: `status: COMPLETE`, `completedAt` set, `executionMode: SIMULATION`.
    `COMPLETE` here means "the transfer was computed and recorded", not "the money
    landed" — no ACH was ever initiated. A dry run the source can't fund is still a
    `201`; the failure rides on the transfer itself, exactly as on a live call.

    ```json
    {
      "data": {
        "id": "7f7b52b5-da88-48b6-a63b-c9bcca12d891",
        "amountInCents": 50000,
        "status": "COMPLETE",
        "executionMode": "SIMULATION",
        "completedAt": "2024-04-25T10:00:00Z"
      },
      "requestId": "req_..."
    }
    ```

    **A simulated rule trigger** returns `202` with an `executionId`, same as a live
    one, and runs asynchronously through the same rule engine. Reading the result takes
    two requests, because the execution record tells you what the rule *did* but never
    how much money it would have moved:

    1. Poll `GET /rules/{ruleId}/executions/{executionId}` until `status` is terminal.
       It reports which step matched (`stepIndexMatched`, or `conditionsNotMet: true`
       if none did) and how many transfers the run produced (`transfersAttempted`,
       `transfersCompleted`, and their ids in `transferIds`) — but no amounts.
    2. `GET /transfers/{id}` for each id in `transferIds` to read `amountInCents` and
       the source and destination.

    `transfersAttempted` counts what the engine *calculated*, so it can exceed the
    number of ids in `transferIds`: a transfer whose calculated amount came out to zero
    is counted but never created — a `round_down` action with nothing left to round, say,
    or a per-period limit already exhausted. So an empty `transferIds` on an execution
    with `transfersAttempted: 1` is a real answer — this rule would move nothing — and
    not a preview that went missing.

    **Previewing a balance the account doesn't hold.** Pass the dry-run-only
    `simulatedSourceBalance` (replaces the balance) or `simulatedIncomingFunds` (adds to
    it, modelling a deposit that hasn't landed yet — this is how to preview an
    `ON_FUNDS_TRANSFERRED` rule). `executeAmount` is *not* a simulation knob: it means
    the same thing on a live trigger as under `simulation: true`, which is precisely what
    makes a dry run a faithful preview of the live call. See the `simulation` field on
    `TriggerRuleRequest` for how the three combine.

    A dry run works on a **deactivated** rule, so you can preview a rule's full
    effect before a human ever turns it on; a live trigger on a disabled rule is
    rejected with `403 RULE_DEACTIVATED`.

    **Simulated rows are invisible to reads by default.** Every list endpoint
    defaults to `executionMode=LIVE`, so pass `executionMode=SIMULATION` (or `ALL`)
    on `GET /transfers`, `GET /accounts/{id}/transfers` and
    `GET /rules/{id}/executions` to see your dry runs. The upside of that default:
    dry runs never pollute what your live integrations and reporting read.


    ### Live rails, $1 at a time

    A dry run cannot tell you how long an ACH transfer actually takes, and that is
    usually the thing you most need to know. So run the real thing at the minimum
    amount — **$1.00 (100 cents)**. You get true settlement timing, real status
    transitions, and real webhook deliveries, on the whole live system, for a dollar
    of exposure. This is the only way to test end-to-end timelines.


    ### A closed system

    Give the integration nowhere to send money. The only way money leaves Sequence
    over the API is a transfer to a connected external account, so if you connect
    none — or connect them but leave them out of the key's `MANUAL_TRANSFER` and
    `TRIGGER_RULES` resource lists — then every account the key can reach is internal
    (pods and income sources) and no mistake it makes can move money out. Fund one
    pod and let your code shuffle that balance as aggressively as you like.


    ### Approval on everything

    Leave **require approval before execution** on for `TRIGGER_RULES` and
    `MANUAL_TRANSFER` — it's the default on a new key, and it's mandatory over OAuth.
    Every money movement your integration attempts then arrives as a proposal you
    approve or deny in the app (see *Human approval for money movement* above), so an
    agent can run wild while you remain the last step. Pass `reasonForApproval` so
    each request explains itself, and actually read it before approving: the prompt is
    the control, not a formality.


    ## Response format

    Every successful response is wrapped:

    ```json
    {
      "data": {  },
      "requestId": "req-42"
    }
    ```

    The `requestId` is the unique handle for the request — include it when
    reporting an issue and we can trace exactly what happened.


    ## Errors

    Errors return the matching HTTP status and a body of:

    ```json
    {
      "error": {
        "code": "ACCESS_DENIED",
        "message": "API key does not have required permissions to access this resource"
      }
    }
    ```

    The `code` is a stable machine-readable identifier; the `message` is a
    human-readable explanation suitable for logs.

    **`400 Bad Request`** — Malformed or invalid input.

    - `INVALID_PARAMETERS` — the request body fails schema validation.
    - `TRANSFER_SOURCE_NOT_FOUND` / `TRANSFER_DESTINATION_NOT_FOUND` — the source or destination account in a transfer body doesn't exist.

    **`401 Unauthorized`** — Missing or invalid API key.

    - `UNAUTHORIZED` — no `Authorization` header, or the bearer token couldn't be resolved.

    **`403 Forbidden`** — The credential is valid but the action isn't allowed.

    - `ACCESS_DENIED` — the key lacks the required permission, or the requested resource is outside the permission's allowed list.
    - `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.
    - `MAXIMUM_AMOUNT_EXCEEDED` — a manual transfer amount exceeds the permission's `max_amount` cap.
    - `RULE_DEACTIVATED` — attempted to trigger a rule that's disabled in the dashboard.
    - `INVALID_RULE` — the rule's trigger type isn't supported via the API, or the rule has been deleted.

    **`404 Not Found`** — The referenced resource doesn't exist or isn't visible to this key.

    - `ACCOUNT_NOT_FOUND`, `RULE_NOT_FOUND`, `RULE_EXECUTION_NOT_FOUND`, `TRANSFER_NOT_FOUND` — entity-specific variants.
    - 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}`.

    **`429 Too Many Requests`** — Rate limit exceeded.

    - `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.

    **`500 Internal Server Error`** — Unexpected server error.

    - `UNEXPECTED_ERROR` — catch-all for unhandled exceptions. Include the `requestId` from the response when reporting it.


    ## Idempotency

    State-changing endpoints accept an optional `idempotency-key` header.
    Sequence remembers the result for 24 hours, so a retry with the same
    key returns the original response without re-running the operation.

    ```
    idempotency-key: 7f0e8a52-2b9f-4ae9-9a4b-9d5b0a3e9a48
    ```

    Use a UUID v4 and generate a fresh one for every distinct intent. This
    matters most for `POST /rules/{id}/trigger` and `POST /transfers`, where
    a retry without an idempotency key can double-spend.


    ## Asynchronous operations

    `POST /transfers` and `POST /rules/{id}/trigger` return immediately after the
    work has been queued. The response includes a resource id with an initial
    `PROCESSING` / `IN_PROGRESS` status — poll `GET /transfers/{id}` or
    `GET /rules/{ruleId}/executions/{id}` to observe the terminal status.

    **Eventual consistency.** Reads on async resources are eventually
    consistent: a very early poll may briefly observe `404
    TRANSFER_NOT_FOUND` / `RULE_EXECUTION_NOT_FOUND` for an id you just
    received from a successful POST. Treat such 404s as transient — wait
    briefly and retry. A 404 on an id you did *not* just receive is final
    (the resource does not exist).

    If a network error interrupts a request before you receive a response, retry
    it using the **same `idempotency-key` value**. The server guarantees
    idempotent processing: if the original request already created the resource,
    the retry returns the same id. If the original is still in flight, the retry
    returns `409 TRANSFER_IN_PROGRESS` / `409 RULE_EXECUTION_IN_PROGRESS` — wait
    briefly and try again.

    **Idempotency-Key retention is 24 hours.** Reusing the same key after that
    window starts a new operation. Reusing the key within the window with a
    *different* request body returns `400 IDEMPOTENCY_KEY_MISMATCH` — generate
    a fresh key for new operations.


    ## Pagination

    List endpoints use offset-based pagination via the `page` and `pageSize`
    query parameters. Responses include a `pagination` object:

    ```json
    {
      "data": {
        "items": [],
        "pagination": { "page": 1, "pageSize": 10, "hasNextPage": false }
      },
      "requestId": "req_..."
    }
    ```

    Defaults: `page=1`, `pageSize=10`. Maximum `pageSize` is `100`.
    Use `pagination.hasNextPage` to detect truncation — when `true`, increment
    `page` and re-fetch to retrieve the next batch.


    ## Caching & polling cadence

    Pick a polling interval that matches how often the underlying data actually
    changes. Faster polling does not yield fresher data and burns your rate-limit
    budget (100 requests/minute per key).

    | Resource | Upstream refresh | Recommended poll |
    |---|---|---|
    | 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**. |
    | 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. |
    | 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. |

    On `429 RATE_LIMIT_EXCEEDED`, honor the `Retry-After` response header and back
    off with jitter.


    ## Money & identifiers

    - **Amounts** are integers in the account currency's minor unit
      (cents for USD). `100000` is $1,000.00.
    - **Minimum transfer amount** is **$1.00 (100 cents)**. Applies to both
      manual transfers (`POST /transfers`) and transfers produced by rule
      actions. A request to move less than $1.00 is rejected.
    - **Timestamps** are ISO 8601 in UTC (e.g. `2024-04-23T09:15:04Z`).
    - **IDs** are UUIDs (e.g. `c4a8e3b7-5d9f-4f1a-8e3d-12345abcdef0`).
      `requestId` returned in every response is a short request handle
      assigned by the API gateway.


    ## Webhooks

    Sequence can deliver events to an external web server whenever certain events occur.

    Register endpoints under [Settings → Webhooks in the dashboard](https://app.getsequence.io/account/webhooks).
    Every endpoint you register will be subscribed to all supported events.

    Your server should respond to Sequence requests with a `2xx` status code. Requests that timed out or got a
    different response code will be retried. We recommended to perform all processing asynchronously in order to
    avoid timeouts.

    ### Payloads

    Sequence webhook event payloads include resource IDs without stateful data load.
    After receiving the webhook, use the included `resource.id` to call the relevant `GET` endpoint
    (e.g. `GET /transfers`) to receive the up-to-date state of the resource.

    ### Signature verification

    Every webhook request carries an `X-Sequence-Signature` header of the form
    `t=<unix-seconds>,v1=<hex>`. In order to verify the webhook was sent by Sequence, recompute
    `HMAC-SHA256(signingSecret, "{t}.{rawRequestBody}")` and compare it against `v1`.
    It is recommended to reject the request if the signature doesn't match,
    or if `t` is more than 5 minutes from your clock (replay protection).

    Note that signing and verification should be performed against the *raw* request-body bytes,
    not a re-serialized object.

    The signing secret is shown **once** when you create the
    endpoint. Store it securely; to rotate it, delete and recreate the endpoint.

    ### Delivery semantics

    Delivery is **at-least-once** with retries and exponential backoff, so you may
    receive the same event more than once over a 24h time period. Each delivery carries a unique
    `X-Sequence-Event-Id`. You can use it to keep event handlers idempotent.

    ### Supported events

    | Event | Description |
    | --- | --- |
    | [`transfer.changed`](#tag/transfers/webhook/POST/transferchanged) | A transfer is created or its status changes |
    | [`card_transaction.changed`](#tag/card-transactions/webhook/POST/card_transactionchanged) | A card purchase, refund, or payout is recorded |
    | [`external_transaction.changed`](#tag/external-transactions/webhook/POST/external_transactionchanged) | A connected-account transaction is first seen or settles (typically updated once a day) |
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:


      - **Transfers (this section)**: money movements where a Sequence account
      is a party,

      such as ACH transfers, check deposits, and movements into, out of, or
      between Sequence

      accounts. Card activity is excluded. `GET /transfers`, `GET
      /transfers/{id}`.


      - **[Card transactions](#tag/card-transactions)**: card movements on
      Sequence-issued cards (`DEBIT_CARD`,

      `OMNI_CARD`) — purchases, refunds, and payouts. `GET /card-transactions`.


      - **[External transactions](#tag/external-transactions)**: movements on
      accounts you've connected to Sequence but that

      Sequence does not manage (via Plaid/Finicity), surfaced for visibility
      only.

      `GET /external-transactions`.


      The same money movement can appear in more than one place (e.g. a
      connected-account transfer

      into a Sequence account shows up as both a transfer and an external
      transaction).
  - name: Card transactions
    description: >
      Sequence tracks three kinds of money movement — make sure you're using the
      right one:


      - **Card transactions (this section)**: card movements on Sequence-issued
      cards

      (`DEBIT_CARD`, `OMNI_CARD`) — purchases, refunds, and payouts. `GET
      /card-transactions`.


      - **[Transfers](#tag/transfers)**: money movements where a Sequence
      account is a party, such as ACH

      transfers, check deposits, and movements into, out of, or between Sequence
      accounts.

      Card activity is excluded. `GET /transfers`, `GET /transfers/{id}`.


      - **[External transactions](#tag/external-transactions)**: movements on
      accounts you've connected to Sequence but that

      Sequence does not manage (via Plaid/Finicity), surfaced for visibility
      only.

      `GET /external-transactions`.


      The same money movement can appear in more than one place (e.g. a
      connected-account transfer

      into a Sequence account shows up as both a transfer and an external
      transaction).
  - name: External transactions
    description: >
      Sequence tracks three kinds of money movement — make sure you're using the
      right one:


      - **External transactions (this section)**: movements on accounts you've
      connected to

      Sequence but that Sequence does not manage (via Plaid/Finicity), surfaced
      for visibility

      only. `GET /external-transactions`.


      - **[Transfers](#tag/transfers)**: money movements where a Sequence
      account is a party, such as ACH

      transfers, check deposits, and movements into, out of, or between Sequence
      accounts.

      Card activity is excluded. `GET /transfers`, `GET /transfers/{id}`.


      - **[Card transactions](#tag/card-transactions)**: card movements on
      Sequence-issued cards (`DEBIT_CARD`,

      `OMNI_CARD`) — purchases, refunds, and payouts. `GET /card-transactions`.


      The same money movement can appear in more than one place (e.g. a
      connected-account transfer

      into a Sequence account shows up as both a transfer and an external
      transaction).
  - 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.
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.
    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.
      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.
  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.


        Each key holds a list of permissions. Every permission names what the
        key is allowed to do

        and which resources it applies to. A request that asks for something
        outside the key's

        permissions returns `403`. Grant the minimum permissions a key needs.


        | Permission | Resources | Grants access to |

        |---|---|---|

        | `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 |

        | `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 |

        | `READ_RULES` | all rules or a specific list of rule IDs | List rules,
        read rule details, and read rule execution history for those rules |

        | `TRIGGER_RULES` | all rules or a specific list of rule IDs | Trigger a
        rule on demand. Can require human approval — see below |

        | `CREATE_AND_EDIT_RULES` | all rules or a specific list of rule IDs |
        Create rules and update existing rules |

        | `READ_TRANSFERS` | all accounts or a specific list of account IDs |
        Read transfer history (requests must filter by `accountId`) |

        | `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 |

        | `READ_AUDIT_LOGS` | `*` (org-scoped) | Read the API key audit log for
        the organization |


        **Human approval.** The two money-movement permissions (`TRIGGER_RULES`,
        `MANUAL_TRANSFER`)

        additionally carry `approval: { required: boolean }`, set from the
        "require approval before

        execution" option when you create the key, defaulting to **on**. When
        required, the call

        succeeds with `status: APPROVAL_PENDING` and an `approvalUrl` instead of
        executing, and an

        owner or co-owner approves or denies in the app. See *Human approval for
        money movement*

        in the overview.


        **MCP OAuth callers** don't hold a key. They get a built-in token whose
        permissions are

        derived from the member's org role; owners and co-owners receive both
        money-movement

        permissions with `approval.required` hardcoded to `true` and no resource
        or amount

        restriction, and other roles receive the read set only. See *Connect via
        MCP* in the

        overview.


        A few read-only endpoints require **no permission** and are available to
        every valid key

        regardless of its scopes: `listBeneficiaries` returns the organization's
        beneficiaries

        (`id`, `name`, `beneficiaryType`) so a key can discover which
        `beneficiaryId` to pass when

        creating accounts.
  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.
      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.
      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`.
      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.
      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.
        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.
        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.
        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.
      properties:
        date:
          type: string
          format: date
          description: >
            The day this balance belongs to. What that means depends on
            `dateAttribution`.
        dateAttribution:
          type: string
          enum:
            - BANK_DATE
            - SYNC_DATE
          description: >
            What `date` represents. These are not interchangeable, and a chart
            mixing them without

            saying so is misleading.


            - `BANK_DATE` — a settled banking day, as closed by the partner bank
            (`POD` and
              `INCOME_SOURCE` accounts). The balance is final for that day.
            - `SYNC_DATE` — the day Sequence captured the balance
            (`EXTERNAL_ACCOUNT` accounts). No
              provider exposes a banking day for these, so this is a capture date and the balance is
              only the freshest value held that day. Use `balance.balanceLastUpdatedAt` to tell whether
              it actually moved.
        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.
        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.
        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.
      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.
    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).

        - `BUSINESS` - a legal business entity (LLC, corporation, sole
        proprietorship, etc.).
    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.
      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).
          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.
      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.

            - `OMNI_CARD` - a Sequence-issued card funded from multiple
            switching Sequence pods.
        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).
            - `MONEY_IN` - funds arriving in the account (refund or payout).
        subtype:
          type: string
          enum:
            - PURCHASE
            - REFUND
            - PAYOUT
          description: |
            The kind of card activity.
            - `PURCHASE` - an outgoing card purchase.
            - `REFUND` - an incoming refund / reverse of a purchase.
            - `PAYOUT` - an incoming push-to-card payout (treated as income).
        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.
        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.
        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).

            - `MONEY_OUT` - funds leaving the account (e.g. a payment or
            withdrawal).
        status:
          type: string
          enum:
            - PENDING
            - COMPLETE
          description: |
            - `PENDING` - the transaction has not yet settled.
            - `COMPLETE` - the transaction is posted/settled.
        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.
        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.
          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.

        - `PARTIAL` - some transfers succeeded and some failed.

        - `FAILED` - execution errored or all transfers failed. A `FAILED`
        execution can still contain
          completed transfers: actions run sequentially against a running source balance, so earlier
          actions may move money before a later one errors. Check `transfersCompleted` and
          `transferIds` rather than inferring from `status` alone.
        - `IN_PROGRESS` - the rule job is still running, a retry is scheduled,
        or transfers have been created but have not yet settled.

        - `APPROVAL_PENDING` - execution is awaiting explicit human approval
        before it can run.

        - `APPROVAL_DENIED` - execution will never run: a human denied it, or it
        went 24 hours
          without a decision and the approval request expired.
    ExecutionMode:
      type: string
      enum:
        - LIVE
        - SIMULATION
      description: |
        - `LIVE` - real money movement
        - `SIMULATION` - dry run; no money moved
    RuleExecutionListMode:
      type: string
      enum:
        - ALL
        - LIVE
        - SIMULATION
      default: LIVE
      description: |
        Filter list results by execution mode. Defaults to `LIVE`.
        - `LIVE` - real rule executions only
        - `SIMULATION` - dry-run rule simulations only (no money moved)
        - `ALL` - both real and simulation rule executions
    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.
        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`.
    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`).
            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.
            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.
    AccountType:
      type: string
      enum:
        - INCOME_SOURCE
        - POD
        - EXTERNAL_ACCOUNT
      description: >
        - `POD` - a Sequence-managed account used for money routing and saving
        toward goals.

        - `INCOME_SOURCE` - a special pod that serves as the entry point for a
        user's funds into Sequence (e.g. where a paycheck lands).

        - `EXTERNAL_ACCOUNT` - an account not managed by Sequence (e.g. a bank,
        credit card, or investment account).
    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`.


            - `DEPOSITORY` - a standard bank account (checking, savings).

            - `INVESTMENT` - an investment account (brokerage, 401k, etc.).

            - `LIABILITY` - a debt account (credit card, student loan, mortgage,
            etc.).
        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.
            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.
            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`.


            - `DEPOSITORY` - a standard bank account (checking, savings).

            - `INVESTMENT` - an investment account (brokerage, 401k, etc.).

            - `LIABILITY` - a debt account (credit card, student loan, mortgage,
            etc.).
        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.
      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.
            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.
            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.
      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.

            - `PER_WEEK` - cumulative cap for the current week (resets every
            Monday). The action is skipped once the cap is reached.

            - `PER_MONTH` - cumulative cap for the current calendar month.

            - `PER_YEAR` - cumulative cap for the current calendar year.
        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`.

            - `DAILY` - runs every day.

            - `WEEKLY` - runs every week.

            - `BI_WEEKLY` - runs on the 1st and 15th of every month
            (semi-monthly, twice a month).

            - `MONTHLY` - runs once a month.

            - `EVERY_OTHER_WEEK` - runs every other calendar week (fortnightly),
            based on even ISO week numbers.
        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.
    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`.
      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.
    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.
        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.
          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).
    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).

                - `SOURCE_ACCOUNT` - percentage of the source account's current
                balance at execution time.
    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.
      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`.
      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.
    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.
      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.
      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.
        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.
          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.
    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).

                - `SOURCE_ACCOUNT` - percentage of the source account's current
                balance at execution time.
    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.
      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`.
      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.
    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.
    RuleConditionFact:
      type: string
      enum:
        - TRANSFER_AMOUNT
        - BALANCE
        - DATE
      description: >
        The value being evaluated on the left side of a condition.


        - `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.

        - `BALANCE` - the current available balance of an account, in cents.
        Specify which account via `params.accountId`; defaults to the trigger
        account if omitted.

        - `DATE` - the current day of the month (1–31). Use with GREATER_THAN /
        LESS_THAN to restrict execution to a date window.
    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.


        - `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.

        - `BALANCE` - the current available balance of an account, in cents.
        Specify which account via `params.accountId`; defaults to the trigger
        account if omitted.

        - `DATE` - the current day of the month (1–31). Use with GREATER_THAN /
        LESS_THAN to restrict execution to a date window.

        - `LAST_DAY_OF_MONTH` - the last day of the month.

        - `NEXT_PAYMENT_MINIMUM_AMOUNT` - the next payment minimum amount of a
        liability account.

        - `LAST_STATEMENT_BALANCE` - the last statement balance of a liability
        account.
    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.
        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.
      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.
      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.

            - `DISABLED` - the rule will not execute under any circumstance.
        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`.


        When `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.
      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.
        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.

            **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`.
        simulation:
          type: boolean
          description: >
            Enables dry run rule execution mode (no money is moved). Defaults to
            `false`.

            When `true`, runs a simulation using current account balances unless

            `executeAmount`, `simulatedSourceBalance` or
            `simulatedIncomingFunds` is provided.

            The rule execution and any transfers it generates are marked

            `executionMode: SIMULATION`.

            Poll the returned `executionId` via the rule-executions and
            transfers APIs.


            **The balance a dry run works from.** Two of the amount fields
            *replace* the

            source balance; one *adds* to it:

                base = (simulatedSourceBalance ?? executeAmount ?? realBalance)
                       + (simulatedIncomingFunds ?? 0)

            `simulatedIncomingFunds` adds because it models money that has **not
            yet landed** -

            a deposit about to arrive on top of whatever the account holds now.

            `simulatedSourceBalance` and `executeAmount` instead state what the
            balance *is*.


            A live run never sums two numbers: it reads the account's real
            balance, which by

            then already includes the deposit that triggered the rule. So
            previewing a $1,000

            deposit into an account holding $500 means `simulatedIncomingFunds:
            100000` against

            the real balance, producing the same $1,500 base a live run reads
            after settlement -

            not `simulatedSourceBalance: 150000`, which would claim the funds
            have already

            settled and leave `percentage` actions with no arriving amount to
            work from.
          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`.
        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.
        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.
    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.
        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.

            - `INCOME_SOURCE` - a special pod that serves as the entry point for
            a user's funds into Sequence (e.g. where a paycheck lands).

            - `EXTERNAL_ACCOUNT` - an account not managed by Sequence (e.g. a
            bank, credit card, or investment account).

            - `EXTERNAL_ENTITY` - an unresolved external participant with no
            Sequence record (e.g. ATM, external ACH pull). Only `name` is
            available; `id` is null.
        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.
    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.
      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.


            - `MONEY_IN` - funds arriving into a Sequence account from outside
            (direct deposit, manual pull from linked account, cashback).

            - `MONEY_OUT` - funds leaving a Sequence account to the outside
            (rule payment, manual transfer to external account, ATM withdrawal).

            - `INTERNAL` - funds moving between two Sequence-owned accounts (pod
            to pod, pod to income source).
        origin:
          type: string
          enum:
            - DIRECT_DEPOSIT
            - CHECK_DEPOSIT
            - CASHBACK
            - USER_PULL
            - RULE
            - USER
            - EXTERNAL_PULL
            - UNKNOWN
          description: >
            What initiated the transfer.


            - `MONEY_IN` origins:
              - `DIRECT_DEPOSIT` - ACH push into a Sequence account from an external source (employer payroll, peer transfer, payout, etc.).
              - `CHECK_DEPOSIT` - paper check deposited to a Sequence account.
              - `CASHBACK` - reward credited by Sequence.
              - `USER_PULL` - user manually pulled funds from a linked external account into Sequence.
            - `MONEY_OUT` origins:
              - `RULE` - outgoing transfer triggered by an automated rule.
              - `USER` - outgoing transfer manually initiated by the user to an external account.
              - `EXTERNAL_PULL` - funds withdrawn externally without going through Sequence (ATM withdrawal, external ACH pull, cleared check).
            - `INTERNAL` origins:
              - `RULE` - internal transfer between Sequence accounts triggered by a rule.
              - `USER` - internal transfer between Sequence accounts manually initiated by the user.
        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`).
        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.
        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.

            - `PROCESSING` - transfer has been created and the internal job is
            actively running; the payment has not yet been submitted to the
            payment network.

            - `PENDING` - payment submitted to the payment network, awaiting
            settlement.

            - `COMPLETE` - settled successfully. Once a transfer reaches this
            status, `completedAt` is present.

            - `INCOMPLETE` - did not complete due to insufficient funds. Once a
            transfer reaches this status, `errorCode` is present.

            - `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.

            - `CANCELLED` - transfer was cancelled before settlement.

            - `APPROVAL_DENIED` - transfer will never be processed: a human
            denied it, or it went
              24 hours without a decision and the approval request expired.
        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:


            - `INSUFFICIENT_FUNDS` - source account had insufficient funds.

            - `DISCONNECTED_ACCOUNT` - the source or destination account was
            disconnected.

            - `NAME_MISMATCH` - the beneficiary name did not match the account
            holder name.

            - `PAYMENT_FAILED` - the payment was rejected by the payment
            network.

            - `PAYMENT_NOT_SUPPORTED` - the account does not support this type
            of payment.

            - `TRANSFER_AMOUNT_LESS_THAN_ONE_DOLLAR` - transfer amount is below
            the $1.00 minimum.

            - `DAILY_ACH_CREDIT_LIMIT_REACHED` - daily ACH credit limit
            exceeded.

            - `MONTHLY_ACH_CREDIT_LIMIT_REACHED` - monthly ACH credit limit
            exceeded.

            - `DAILY_ACH_DEBIT_LIMIT_REACHED` - daily ACH debit limit exceeded.

            - `MONTHLY_ACH_DEBIT_LIMIT_REACHED` - monthly ACH debit limit
            exceeded.

            - `NULL_BALANCE` - source account balance was unavailable at
            execution time.

            - `ACCOUNT_NO_MINIMUM_PAYMENT_AMOUNT` - liability account has no
            minimum payment amount on record.

            - `ACCOUNT_NO_LAST_STATEMENT_BALANCE` - liability account has no
            last statement balance on record.

            - `RESOURCE_DELETED` - source or destination account was deleted
            before the transfer completed.
        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.
        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`.
    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

            note or memo). Hard cap: 10 characters, letters/digits/spaces only.
            This limit

            comes from ACH/NACHA constraints enforced by the underlying payment
            provider.
        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.
        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.
    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

            their own routing and account numbers, so an outside deposit can be
            pointed at either

            (those numbers are shown in the Sequence app; this API does not
            return them for either

            type). The difference is what the account is *for*:

            - `POD` - a savings/goal bucket (e.g. Vacation, Tax Reserve),
            usually funded by
              transfers or rules from elsewhere in Sequence. Supports an optional
              `savingsTargetInCents`.
            - `INCOME_SOURCE` - the entry point where outside money is meant to
            land (e.g. a
              paycheck, direct deposit, or client payment); rules then distribute what arrives.
              The only type that supports in-app payroll switching.
        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.
          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.
          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.
        savingsTargetInCents:
          type:
            - integer
            - "null"
          minimum: 0
          description: >
            Savings goal in cents. **Pods only** — supplying this with `type:
            INCOME_SOURCE` returns `400 INVALID_PARAMETERS`.
    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).
      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.
      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.
                      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.
            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.
              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.
              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).
            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)`.
              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.
      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.
  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.
      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.
  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.
      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.
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.
      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.
      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`.
          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.
          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`).
          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`).
          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.


        This 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.
      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.
          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.


        Both 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.


        The 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).
      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`.
          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.


            `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.
          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.


        Only 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.
      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.
      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.
                      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`.
                  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`).
          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:

            - `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.

            - `INVALID_RULE` - the rule's trigger type is not supported by this
            endpoint, or the rule has been deleted.

            - `ACCESS_DENIED` - the API key does not have the required
            `TRIGGER_RULES` permission for this rule.

            - `KYC_REQUIRED` - the organization has not completed identity
            verification, so it owns no rules to trigger.
          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.
          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.
      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.
          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.
      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.
      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.
          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.
      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.
          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`).
          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`).
          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.
      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.
      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.


        Each 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.


        `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.


        Results 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 `*`).
      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).


            Always use bracket notation (`accountIds[]`). For multiple IDs you
            can also repeat the key:

            ```

            GET /platform/v1/transfers?accountIds[]=uuid1

            GET /platform/v1/transfers?accountIds[]=uuid1&accountIds[]=uuid2

            GET /platform/v1/transfers?accountIds=uuid1&accountIds=uuid2

            ```
          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.
          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`).
          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`).
          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.
      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`).
          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.
          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.


        Each 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).


        Unlike 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.


        This 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 `*`).
      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).

            Always use bracket notation (`accountIds[]`). For multiple IDs you can also repeat the key:
            ```
            GET /platform/v1/external-transactions?accountIds[]=uuid1
            GET /platform/v1/external-transactions?accountIds[]=uuid1&accountIds[]=uuid2
            GET /platform/v1/external-transactions?accountIds=uuid1&accountIds=uuid2
            ```
          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`.
          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.
          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 `*`).
      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.
      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.
          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.
          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.
          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 `*`).
      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.
      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`.
          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.


        The 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`.
      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"
