Skip to main content
BETA — SUBJECT TO CHANGE. This API is in beta and may change without notice.
A transfer moves cash between your partner funding account and a participant account under your Firm. It is the only way money enters or leaves a participant account outside of trading itself, and it exists for exactly three reasons: Direction is fixed by the reason. You name only the participant account; the platform resolves your funding account from your firm’s configured funding relationship and derives the source and destination from the reason. There is no way to express any other movement — transfers to your firm, between participants, or to an external destination are structurally impossible.

Service

Service: polymarket.us.cashmovement.v1.CashMovementService Transfers are firm-scoped — do not send x-participant-id. Your firm submits transfers on behalf of your funding entity under the three-party agreement; the platform verifies your firm is authorized for the funding account on every call.

CreateCashMovement

GetCashMovement

The read model returns the typed reason and derived source and destination accounts, but it does not echo participant_account_id, external_reference, or memo. Persist those request fields in your own ledger alongside workflow_id. There are no order, execution, or market correlation fields on a transfer. Both sides of a confirmed transfer appear on the balance ledger of the affected accounts, so your projection and your funding entity’s records see the same event.

Insufficient funds

A transfer is rejected if the source account cannot cover the amount: This is enforced across the system regardless of reason — no transfer can drive an account negative. Managing the risk is on you and your funding entity: gate spendable balance so accrued fees stay covered (Vendor Fees), and check free cash before initiating withdrawals (Deposits & Withdrawals).

Frequency rules

Transfers are a limited, shared resource — see the transfer budget:
  • DEPOSIT / WITHDRAWAL — event-driven: typically one transfer per wallet deposit/withdrawal event per participant. Mirroring wallet events 1:1 is the intended pattern; batch micro-events into fewer, larger transfers where your product allows.
  • VENDOR_FEESat most once per day per participant account. Collecting weekly or monthly is fine; collecting more often than daily is not permitted.

Rate limits and smoothing

Budget for a maximum of 5 transfer calls per second across your whole integration. Requests over the limit are rejected with gRPC RESOURCE_EXHAUSTED (HTTP 429 on any REST mapping) — the transfer was not created, and it is always safe to retry with the same idempotency_key. Design for the budget rather than reacting to rejections:
  • Single dispatcher, client-side queue. Route every transfer through one queue per environment drained at a fixed rate below the cap (e.g. 4/s, leaving headroom for retries). Never fan transfers out from concurrent workers straight to the API.
  • Spread scheduled runs. An end-of-day vendor fee collection across 2,000 participant accounts at 4/s takes ~8–9 minutes — schedule the run as a paced drain, not 2,000 simultaneous calls at the stroke of EOD.
  • Retry with backoff and the same key. On RESOURCE_EXHAUSTED, re-enqueue with jittered exponential backoff (e.g. 1s → 2s → 4s, ±20% jitter) and the same idempotency_key. The rejection happened before creation, so the retry is a fresh, safe attempt.
  • Deposits preempt fee collections. If a participant is waiting to trade, their deposit is latency-sensitive; a fee collection is not. Give DEPOSIT transfers priority in your queue and let batch runs yield.

Idempotency and recovery

  • Use a distinct, durable idempotency key per logical transfer, persisted before the call.
  • A transport timeout or an AMBIGUOUS status is not permission to create a second workflow — replay the same create request with the same key, or read the original workflow by workflow_id.
  • A replay must be identical: the request is hashed under the key, so retrying with a changed amount, account, reason, or reference is rejected as key reuse with a different request.
  • Use bounded recovery for PENDING workflows rather than a permanent polling scheduler.
  • Persist workflow_id, the reason, and external_reference through a terminal result — they are your join keys across your books, the balance ledger, and support requests.

Errors

An insufficient-funds outcome is not a gRPC error at create time: the workflow resolves to status = REJECTED with a rejection_reason — see Insufficient funds.

Partner Funding Overview

The model — parties, money flows, and directional guarantees.

Deposits & Withdrawals

Mirroring wallet allocations into buying power.

Vendor Fees

Accrual, the daily report, and collection.

Reconciliation

Keeping your books in sync with the ledger.