> ## Documentation Index
> Fetch the complete documentation index at: https://partners.docs.polymarket.us/llms.txt
> Use this file to discover all available pages before exploring further.

# Funding and transfers

> Pre-position a pool, move cash into a participant account with CashMovementService, and handle the residue you cannot move.

Pre-position a pooled balance with us and move cash from it into a participant account one transfer at a time; trading proceeds and settlement credits stay in the participant account. This page covers the model, the one RPC that moves cash, and the sub-cent residue that model leaves behind.

<Info>
  **Before this page**

  * Your firm's API credentials work against the gRPC target for your environment, and you can mint an access token holding the `write:cash-movements` grant — see [Authentication](/authentication).
  * You know which of your two firms is which — see [Firms, participants and accounts](/identity).
  * At least one participant has reached `kyc.approved`, and you recorded its `participantId` and its `provisionedAccount` — see [KYC flow](/kyc).
</Info>

<Snippet file="beta.mdx" />

<Info>
  **API reference:** <a href="https://docs.polymarket.us/institutional/funding/overview" target="_blank" rel="noreferrer">Funding</a>. Opens on the public documentation site in a new tab.
  Where it disagrees with this page, this page is authoritative for the partner surface.
</Info>

## The funding model

<Tabs>
  <Tab title="ISV">
    ### The model

    Cash is pre-positioned so that a user who just deposited in your app is not paced by a bank rail: you fund your pool in advance, and each order is funded from it by a transfer into the user's participant account.

    ### The three parties

    | Party                                            | Holds                                                                                                                    | Read it with                                                                                          |
    | ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------- |
    | Your firm, through your Wallet Co funding entity | the pooled balance you pre-position                                                                                      | `GetFundingAccountBalance`                                                                            |
    | Your end user, as a participant                  | their cash, their positions, their settlement credits, in a participant clearing account under your **participant** firm | `GetAccountBalance`, with the gap on [Which number is spendable](/balances#which-number-is-spendable) |
    | Us, as DCM and DCO                               | the accounts themselves, and the funding relationship between your funding account and each participant                  | —                                                                                                     |

    You do not hold customer funds, and an omnibus account at our DCO is **not available to ISVs**. Every end-user dollar sits either in your pool or in that user's participant clearing account, never in an account of yours that mixes users.

    Cash movement is **firm-scoped**: you name only the participant account and we resolve your funding account from the relationship established at KYC. Do not send `x-participant-id` on these calls. The mechanics are under [Move cash](#move-cash).

    ### Your funding entity must exist first

    Your Wallet Co funding entity must exist and be active **before your firm's API credentials are enabled**. There is no order of operations in which you integrate against a live credential and add the funding entity afterwards.

    ### Removed 2026-08-06

    <Warning>
      **`CreateFundedOrder`, `PreviewFundedOrder` and `OdfSweep` were removed on 2026-08-06, and the
      removal shipped with no changelog entry.** If your money path calls any of the three, it is broken
      and no announcement told you so. One partner discovered the removal through gRPC reflection after
      their whole money path stopped working.

      **What replaces them:** `CreateVendorOrder` for the order, plus a transfer on
      `CashMovementService` for the cash. There is no funded-order preview on the partner surface. There
      is no sweep: settlement credits, realized profit and released collateral stay in the participant's
      clearing account and become buying power there, so nothing needs sweeping after a fill or a
      settlement.

      The proto reference is consistent with the removal — `OrderEntryAPI` declares exactly
      `CreateOrderSubscription`, `InsertOrder` and `CancelOrder`. Note that gRPC server reflection is
      entitlement-gated and returns `PermissionDenied: method not permitted` without the grant, so
      reflection is not a reliable way to check what you still have.
    </Warning>

    <Warning>
      **Do not credit your user from your own ledger on the strength of this page.** We credit the
      participant's clearing account at resolution. Who pays the user, and from which side, is settled on
      [Who credits the user](/settlement#who-credits-the-user) and nowhere else.
    </Warning>

    ### Rails you cannot use

    `CheckoutAPI` and Aeropay are **not entitled for ISVs**. Both return `403 method not permitted`. Do not build a deposit UX against either; the 403 is the entitlement, not a misconfiguration on your side.

    ### Rails you can use

    Production deposits into your pool are **wire only**, as of August 2026. There is no card, ACH or wallet rail on the ISV funding path.

    Pre-production pools are funded manually by us on a Slack request. There is no self-service test funding, so plan a preprod pool top-up as a human step with a lead time, not as a scripted fixture.
  </Tab>

  <Tab title="Introducing broker">
    **You may not accept or hold customer funds.** The money structure is otherwise the same as an
    ISV's, with one identity added: the **IB anchor DCO account**, your clearing identity. Wallet Co
    and the pooled balance are not additions — an ISV has both. What you carry on top is a **Wallet
    Co segregation requirement**, and it is not specified in writing, so get it confirmed.

    The flow has exactly one shape. You pre-position your own funds in a pooled balance with us, then
    move cash into a participant's clearing account with a `Transfer`. The cash stays there — fills,
    realized profit, released collateral and settlement credits all land in the participant's account
    and become buying power, so nothing needs sweeping after a fill or a settlement. Transfers to your
    own firm, between participants, or to an external destination are structurally impossible, which is
    also what stops you building a path that has you holding customer money.

    Production deposit rails are **wire only** as of August 2026.

    <Note>
      Read [Funds handling](/funds) before you build. It records the omnibus position, the Wallet Co
      segregation requirement, and the precision rule that keeps your balance sheet from reaching zero.
    </Note>
  </Tab>
</Tabs>

## Move cash

<Note>
  **If you are an IB, this differs.**
  For an ISV the pool is a working-capital question. **For you it is the whole of the permitted
  structure**, because you may not accept or hold customer funds at any point — see
  [Funds handling](/funds). Wallet Co segregation is a prerequisite and is unspecified in
  writing, so get it confirmed. The sub-cent residue below is a **reporting** problem for you,
  not only a reconciliation annoyance — see [Reporting pack](/regulatory#reporting-pack).
</Note>

Move cash between your funding pool and one participant account with `CashMovementService`, and read the outcome off the returned status.

### The service

`CashMovementService` has three RPCs. `CreateCashMovement` is the one that moves cash.

<Warning>
  **Not yet published.** The other two RPCs on `CashMovementService` are not enumerated in anything we
  have published, and the service itself is **absent from the published proto bundle** — the bundle
  advertises 14 services and defines 5, and this is one of the omissions.

  Use the proto your integration lead sent you, and confirm the RPC list with them before you build a
  client around it.
</Warning>

`CashMovementService` is **firm-scoped**. Do **not** send `x-participant-id` on any call to it. That header is required on account-scoped reads such as positions and reports, and sending it here is wrong rather than harmless.

<Snippet file="participant-id-warning.mdx" />

### Direction is fixed by the reason

You do not name a source and a destination. You name the **reason**, and the reason fixes the direction. You name only the participant account; we resolve your funding account from the relationship established server-side at KYC.

| Reason                      | Direction                                                                                                                          |
| --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `DEPOSIT`                   | your funding account → the participant account                                                                                     |
| `WITHDRAWAL`                | the participant account → your funding account                                                                                     |
| `VENDOR_FEES` **\[VERIFY]** | the participant account → your funding account, for fees you have accrued **\[VERIFY]** — see [Vendor fees](/balances#vendor-fees) |

<Warning>
  **\[VERIFY] — the per-reason directions above are inferred, not published.** What is published is
  that **direction is fixed by the reason** and that the three reasons are `DEPOSIT`, `WITHDRAWAL` and
  `VENDOR_FEES`. The direction each one resolves to is not stated anywhere, and `VENDOR_FEES` is the
  one to confirm first: nothing published says whether it debits the participant account, the pool, or
  something else.

  Confirm all three with your integration lead before you move money on this table, and test each
  reason in preprod against the balance ledger rather than against this page.
</Warning>

Three transfers you may be planning are **structurally impossible**, not merely unsupported: a transfer to your own firm, a transfer between two participants, and a transfer to any external destination. There is no field on the request that could express them, so do not design a product flow that needs one.

### Create a transfer

<Note>
  **There is no REST path for `CashMovementService`.** Every call in this section is gRPC against
  `grpc-api.{env}.polymarketexchange.com:443`. The command-line tab below is `grpcurl` with a local
  proto file rather than `curl`, and it passes `-proto` because gRPC server reflection is
  entitlement-gated and returns `PermissionDenied: method not permitted` without the grant.
</Note>

<Warning>
  **Not yet published.** These identifiers on the request and response are not in anything we have
  published, so confirm each against your proto copy before you compile:

  The field names that **are** confirmed and used below are `transfer` (field 4 on the request),
  `amount` and `idempotency_key`, and the reason values `DEPOSIT`, `WITHDRAWAL` and `VENDOR_FEES`.
</Warning>

<CodeGroup>
  ```python Python theme={null}
  import uuid
  from polymarket_auth import PolymarketClient  # published on /connect#authentication

  # protoc output from the CashMovementService proto your integration lead sent you.
  from pmx_protos import cash_movement_pb2 as cm
  from pmx_protos import cash_movement_pb2_grpc as cm_grpc

  # The gRPC target is GRPC_TARGET in polymarket_auth.py — one place, both environments.
  pmx = PolymarketClient()

  PARTICIPANT_ACCOUNT = "firms/.../accounts/..."  # provisionedAccount, recorded at onboarding
  AMOUNT = "25.00"                                # USD decimal string, at most 2 decimal places

  TERMINAL = ("CONFIRMED", "REJECTED")

  def create_deposit(idempotency_key: str) -> str:
      with pmx.channel() as channel:
          stub = cm_grpc.CashMovementServiceStub(channel)
          response = stub.CreateCashMovement(
              cm.CreateCashMovementRequest(
                  idempotency_key=idempotency_key,
                  transfer=cm.Transfer(
                      account=PARTICIPANT_ACCOUNT,
                      amount=AMOUNT,
                      reason=cm.DEPOSIT,
                  ),
              ),
              # Firm-scoped: pass NO participant ID, so no x-participant-id header.
              metadata=pmx.metadata(),
          )
      status = cm.CashMovementStatus.Name(response.status)
      if status not in TERMINAL:
          # PENDING or AMBIGUOUS. Keep this key, do not mint a new one, and reconcile.
          raise RuntimeError(f"unresolved cash movement {idempotency_key}: {status}")
      if status == "REJECTED":
          raise RuntimeError(f"rejected {idempotency_key}: {response.rejection_reason}")
      return status

  print(create_deposit(str(uuid.uuid4())))
  ```

  ```typescript TypeScript theme={null}
  import { randomUUID } from "node:crypto";
  import { PolymarketClient } from "./polymarketAuth"; // published on /connect#authentication

  // protoc output from the CashMovementService proto your integration lead sent you.
  import { CashMovementServiceClient } from "./gen/cash_movement";

  // The gRPC target is GRPC_TARGET in polymarketAuth.ts — one place, both environments.
  const pmx = new PolymarketClient();

  const PARTICIPANT_ACCOUNT = "firms/.../accounts/..."; // provisionedAccount, recorded at onboarding
  const AMOUNT = "25.00"; // USD decimal string, at most 2 decimal places

  const TERMINAL = new Set(["CONFIRMED", "REJECTED"]);

  export async function createDeposit(idempotencyKey: string): Promise<string> {
    const client = new CashMovementServiceClient(pmx.channel());
    const response = await client.createCashMovement(
      {
        idempotencyKey,
        transfer: { account: PARTICIPANT_ACCOUNT, amount: AMOUNT, reason: "DEPOSIT" },
      },
      // Firm-scoped: pass NO participant ID, so no x-participant-id header.
      await pmx.metadata(),
    );

    if (!TERMINAL.has(response.status)) {
      // PENDING or AMBIGUOUS. Keep this key, do not mint a new one, and reconcile.
      throw new Error(`unresolved cash movement ${idempotencyKey}: ${response.status}`);
    }
    if (response.status === "REJECTED") {
      throw new Error(`rejected ${idempotencyKey}: ${response.rejectionReason}`);
    }
    return response.status;
  }

  createDeposit(randomUUID()).then(console.log);
  ```

  ```bash grpcurl theme={null}
  #!/usr/bin/env bash
  set -euo pipefail

  GRPC_TARGET="grpc-api.preprod.polymarketexchange.com:443"  # prod: grpc-api.prod.polymarketexchange.com:443
  PROTO_FILE="./cash_movement.proto"                          # the proto your integration lead sent you
  PROTO_PACKAGE="$(grep -m1 '^package' "$PROTO_FILE" | sed 's/package \(.*\);/\1/')"
  PARTICIPANT_ACCOUNT="firms/.../accounts/..."                # provisionedAccount, recorded at onboarding
  AMOUNT="25.00"                                              # USD decimal string, max 2 decimal places
  IDEMPOTENCY_KEY="$(uuidgen)"
  TOKEN="$(./token.sh)"                                       # the script on /connect#authentication

  # No x-participant-id header: CashMovementService is firm-scoped.
  RESPONSE="$(grpcurl -proto "$PROTO_FILE" \
    -H "authorization: Bearer ${TOKEN}" \
    -d "{\"idempotency_key\":\"${IDEMPOTENCY_KEY}\",\"transfer\":{\"account\":\"${PARTICIPANT_ACCOUNT}\",\"amount\":\"${AMOUNT}\",\"reason\":\"DEPOSIT\"}}" \
    "$GRPC_TARGET" "${PROTO_PACKAGE}.CashMovementService/CreateCashMovement")"

  echo "$RESPONSE"
  STATUS="$(echo "$RESPONSE" | jq -r .status)"
  case "$STATUS" in
    CONFIRMED) exit 0 ;;
    REJECTED)  echo "rejected ${IDEMPOTENCY_KEY}; use a NEW key for any further attempt" >&2; exit 1 ;;
    *)         echo "unresolved ${IDEMPOTENCY_KEY}: ${STATUS}; keep this key and reconcile" >&2; exit 2 ;;
  esac
  ```

  ```go Go theme={null}
  package main

  import (
  	"context"
  	"fmt"
  	"log"

  	"github.com/google/uuid"
  	"google.golang.org/grpc/metadata"

  	// Canonical client from /connect#authentication. The gRPC target is
  	// pmauth.GRPCTarget — one place, both environments.
  	pmauth "example.com/yourfirm/pmauth"

  	cm "yourfirm/pmxprotos/cashmovement"
  )

  const (
  	participantAccount = "firms/.../accounts/..." // provisionedAccount, recorded at onboarding
  	amount             = "25.00"                  // USD decimal string, at most 2 decimal places
  )

  // One auth client for the life of the process: it caches the token and re-mints
  // at expires_in minus 30 s.
  var pm = pmauth.New()

  func createDeposit(ctx context.Context, idempotencyKey string) (string, error) {
  	conn, err := pm.Channel()
  	if err != nil {
  		return "", err
  	}
  	defer conn.Close()

  	// Firm-scoped: pass "" for the participant ID, so no x-participant-id header.
  	md, err := pm.Metadata("")
  	if err != nil {
  		return "", err
  	}

  	resp, err := cm.NewCashMovementServiceClient(conn).CreateCashMovement(
  		metadata.NewOutgoingContext(ctx, md),
  		&cm.CreateCashMovementRequest{
  			IdempotencyKey: idempotencyKey,
  			Transfer: &cm.Transfer{
  				Account: participantAccount,
  				Amount:  amount,
  				Reason:  cm.CashMovementReason_DEPOSIT,
  			},
  		})
  	if err != nil {
  		return "", err
  	}

  	switch status := resp.GetStatus().String(); status {
  	case "CONFIRMED":
  		return status, nil
  	case "REJECTED":
  		return status, fmt.Errorf("rejected %s: %s", idempotencyKey, resp.GetRejectionReason())
  	default:
  		// PENDING or AMBIGUOUS. Keep this key, do not mint a new one, and reconcile.
  		return status, fmt.Errorf("unresolved %s: %s", idempotencyKey, status)
  	}
  }

  func main() {
  	status, err := createDeposit(context.Background(), uuid.NewString())
  	if err != nil {
  		log.Fatal(err)
  	}
  	fmt.Println(status)
  }
  ```
</CodeGroup>

Response, with the field you branch on:

```json theme={null}
{
  "status": "PENDING"
}
```

### The four statuses

| Status      | What it means                                                                                                      | What you do                                                                                                                                                                               |
| ----------- | ------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `PENDING`   | Non-terminal. **\[VERIFY]** — what it asserts about the movement is not published, so do not read it as "accepted" | Do not treat the cash as available and do not tell your user it went through. Wait for a terminal state on the balance-ledger stream — see [Reconciling cash](/balances#reconciling-cash) |
| `CONFIRMED` | Terminal. The cash moved                                                                                           | Release the funds in your own ledger                                                                                                                                                      |
| `REJECTED`  | Terminal. The cash did not move                                                                                    | Read `rejection_reason`, fix the cause, and retry with a **new** `idempotency_key`                                                                                                        |
| `AMBIGUOUS` | We could not determine the outcome. Unresolved, not failed                                                         | Do not re-send with a new key and do not credit or debit your user. Reconcile the account against the balance ledger, then act on what the ledger says                                    |

<Warning>
  **Not yet published.** The `CashMovementStatus` enum is never defined and the `rejection_reason`
  values are never listed, on three pages that reference them. There is also no published deadline by
  which a `PENDING` or `AMBIGUOUS` movement becomes terminal, and no status-lookup RPC on the partner
  surface.

  Treat anything non-terminal as money in flight that only the balance ledger can settle, and ask your
  integration lead for the resolution procedure before you go live.
</Warning>

### Idempotency

The dedupe key is `idempotency_key`. What is established is the **terminal-rejection** case: a terminally-rejected key replays its stored rejection instead of making a fresh attempt.

<Warning>
  **\[VERIFY] — replay is established for terminally-rejected keys only.** Whether a retry on a key
  whose movement is `PENDING`, `AMBIGUOUS` or `CONFIRMED` replays, is rejected, or starts a second
  attempt is not published.

  So do not treat "retrying is safe" as a general property. Key `idempotency_key` off your own
  user-action row, retry the same key on a non-terminal movement, and reconcile against the balance
  ledger rather than against a retry's response.
</Warning>

<Warning>
  **A terminally-rejected `idempotency_key` replays its stored rejection.** After a `REJECTED`
  response, retrying the same key returns that same rejection forever, no matter what you fixed in
  between. **Use a new `idempotency_key` for the next attempt.** This is the most common way a partner
  concludes a fixed problem is not fixed.

  The inverse holds for anything non-terminal: keep the key you have. Minting a new key for a
  `PENDING` or `AMBIGUOUS` movement creates a **second** transfer.
</Warning>

### Two decimal places

`amount` accepts **at most 2 decimal places**. Balances carry more, and have been observed at `172.395` and `1377.57275`. Never round a balance up to construct an `amount`; the consequences and the interim practice are under [Sub-cent balances](#sub-cent-balances).

### Rate limit

<Warning>
  **Not yet published.** The transfer rate limit is being confirmed, and three different statements are
  live today: they disagree on the number **and** on the scope, with at least one of them scoping the
  ceiling across all partners rather than per firm.

  Do not size your order pipeline from any number you have been given verbally. Build backpressure and
  a retry queue in front of `CreateCashMovement`, honour whatever retry delay the error carries, and
  confirm the value and its scope with your integration lead before a launch that depends on
  throughput. This limit blocked one partner's entire order flow.
</Warning>

## Sub-cent balances

Balances carry more decimal places than transfers accept, so there is a residue you cannot move. Before you act on this section, know which balance figure you are reading — see [Which number is spendable](/balances#which-number-is-spendable).

### The numbers

* Balances carry **more than two decimal places**. Observed values: `172.395` and `1377.57275`.
* `amount` on a transfer accepts **at most two decimal places**.

### The consequence

**Your balance sheet cannot reach zero today.** A participant account holding `172.395` can be drained to `172.39` by one `WITHDRAWAL` and no further. The residue is real cash in a real account that no call on the partner surface can move, and there is no sanctioned handling for it.

<Warning>
  **Not yet published.** There is no sanctioned treatment of the sub-cent residue: no rounding rule, no
  sweep, and no statement of whether the residue is ever swept by us.

  Confirm the current answer with your integration lead before you sign off a zero-balance
  requirement with your own finance team or an auditor.
</Warning>

### Interim practice

Do these three things until the sanctioned answer exists.

<Steps>
  <Step title="Track the residue in your own ledger">
    Carry the full-precision balance and the two-decimal transferable amount as separate columns per
    account. The difference is the residue. Parse money as a decimal type, never as a float you then
    round — `int64` fields are serialized as strings in JSON for the same reason.
  </Step>

  <Step title="Never round up into a transfer">
    Truncate toward zero when you derive `amount` from a balance. Rounding `172.395` up to `172.40`
    asks for cash that is not there, and the failure lands on a money path rather than in your tests.
  </Step>

  <Step title="Reconcile the difference as a known standing balance">
    Close your daily reconciliation with the residue as an expected, named line rather than as a
    break. A per-account residue under one cent that does not change between runs is the correct
    state today, not a defect to chase.
  </Step>
</Steps>

## What can go wrong

| Where             | Symptom                                                                   | Cause                                                                                                                                                                                                                                                                       | What you do                                                                                                                                                                                                                                                                        |
| ----------------- | ------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| The funding model | Your funded-order call has stopped working and nothing was announced      | `CreateFundedOrder`, `PreviewFundedOrder` and `OdfSweep` were removed 2026-08-06 with no changelog entry                                                                                                                                                                    | Move to `CreateVendorOrder` plus a transfer. See [Move cash](#move-cash) and [Place an order](/orders)                                                                                                                                                                             |
| The funding model | `403 method not permitted` from `CheckoutAPI` or Aeropay                  | Neither is entitled for ISVs                                                                                                                                                                                                                                                | Stop calling them. Use wire deposits into your pool                                                                                                                                                                                                                                |
| The funding model | Credentials issued but no cash can be positioned                          | Your Wallet Co funding entity is not active yet                                                                                                                                                                                                                             | Confirm the funding entity is active with your integration lead before you schedule integration work                                                                                                                                                                               |
| The funding model | `PermissionDenied: method not permitted` on gRPC reflection               | Reflection is entitlement-gated                                                                                                                                                                                                                                             | Work from the proto files your integration lead sent you, not from reflection                                                                                                                                                                                                      |
| The funding model | Preprod pool is empty and you cannot top it up                            | Preprod funding is a manual step on our side                                                                                                                                                                                                                                | Request the top-up in your shared Slack channel and treat it as a lead-time item                                                                                                                                                                                                   |
| Move cash         | `NOT_FOUND: customer relationship claim failed`                           | The funding relationship is not in place. Three root causes seen: the same test SSN reused across users, so they all point at one exchange account; an incomplete server-side setup step; a half-provisioned firm that can read the pool but cannot move anything out of it | There is **no claim or link RPC in the protos** — you cannot fix this from your side. Check first whether you reused an SSN across test users; that one needs manual DB cleanup by us. Otherwise report the participant account and `idempotency_key` in your shared Slack channel |
| Move cash         | The same rejection keeps coming back after you fixed the cause            | The terminal rejection is stored against your `idempotency_key` and replayed                                                                                                                                                                                                | Retry with a **new** `idempotency_key`                                                                                                                                                                                                                                             |
| Move cash         | Error names `amount` although you sent a valid amount                     | Stale proto. `transfer` is **field 4** in the real service; the published proto omitted an intent occupying field 2 and renumbered `transfer` down, so a valid `"20.00"` arrives as that internal intent                                                                    | Use a proto in which `transfer` is field 4, and regenerate your stubs                                                                                                                                                                                                              |
| Move cash         | `PERMISSION_DENIED`                                                       | Scopes are granted server-side against your client. You cannot request `write:cash-movements` on the token exchange                                                                                                                                                         | Ask for the grant, then **re-mint your token** — an existing token does not pick up a new grant                                                                                                                                                                                    |
| Move cash         | A second transfer appears for one user action                             | A new `idempotency_key` was minted while the first movement was `PENDING` or `AMBIGUOUS`                                                                                                                                                                                    | Key `idempotency_key` off your own user-action row, not off a fresh UUID per attempt                                                                                                                                                                                               |
| Move cash         | `403 method not permitted`                                                | You are calling `CheckoutAPI` or Aeropay, neither of which is entitled for ISVs                                                                                                                                                                                             | See [The funding model](#the-funding-model)                                                                                                                                                                                                                                        |
| Move cash         | Cash movement call fails with a permission error only in some code paths  | `x-participant-id` is being attached by shared client middleware                                                                                                                                                                                                            | Strip the header on `CashMovementService`. It is firm-scoped                                                                                                                                                                                                                       |
| Sub-cent balances | A full-withdrawal transfer fails and the account looked exactly drainable | `amount` was rounded up from a balance carrying more than two decimals                                                                                                                                                                                                      | Truncate toward zero when deriving `amount`                                                                                                                                                                                                                                        |
| Sub-cent balances | Daily reconciliation shows a persistent sub-cent break per account        | The residue is unmovable on the partner surface                                                                                                                                                                                                                             | Report it as a known standing balance, not a break                                                                                                                                                                                                                                 |
| Sub-cent balances | Residue grows instead of staying flat                                     | Something other than precision is moving cash in that account                                                                                                                                                                                                               | Reconcile that account against the balance ledger — see [Reconciling cash](/balances#reconciling-cash)                                                                                                                                                                             |

<Snippet file="support.mdx" />

## Next

[Balances, fees and reconciliation](/balances)
