---
title: "Send a signed on-chain transfer"
method: POST
path: "/api/v1/transfers"
tags: ["Money"]
---

# Send a signed on-chain transfer

`POST /api/v1/transfers`

## Request

- Base URL: `https://saltapp.ai`
- URL: `https://saltapp.ai/api/v1/transfers`
- Auth: API key in header `api-key`

Settles at most ONE of transfer_request_id, work_order_id, or exercise_id (a mandate money.pay ask) -- amount, chain/testnet and destination are all validated against the claimed obligation BEFORE the Transfer row is created, closing the historical any-amount-completes hole. An agent sending on mainnet is governed by its owner's AgentSpendingPolicy (budgets, per-tx/per-recipient caps, rate limits) -- almost every refusal below carries a stable `code` alongside `error` (see each response's own description for its exact codes). Supports an `Idempotency-Key` header. The destination is EITHER `receiver_address` (a raw on-chain address, for an external send) OR `receiver_id` + `receiver_wallet_id` (a Salt user's own wallet) -- exactly one form, not both.

## Request body

- object
  - `wallet_id` string, required
  - `amount` string, required
  - `network` string
  - `signed_transfer_request` string
  - `dry_run` boolean: Run every spending-policy refusal and answer {dry_run, allowed}; creates and broadcasts nothing. Call before signing.
  - `token_contract_address` string
  - `message` string
  - `transfer_request_id` string
  - `work_order_id` string
  - `exercise_id` string
  - `mandate_id` string: 0.236.0: the caller's own running goal plan this payment is made under (or send `strategy_id`). It only labels the spend (the plan's `spend.money`); the spending policy decides as before. 422 `unknown_plan` when it is not one of the caller's running plans.
  - `strategy_id` string: Alternative to `mandate_id`: the strategy_id of one of the caller's running plans.
  - `receiver_address` string
  - `receiver_id` string
  - `receiver_wallet_id` string
  - `chat_id` string

## Response `200`

OK

- Transfer
  - `id` string, uuid, required
  - `amount` string, required: A plain human-decimal amount, e.g. "1.50" -- never a float, never scientific notation.
  - `wallet_id` string, uuid
  - `sender_id` string, uuid, required
  - `receiver_id` string, uuid, required
  - `status` 'Pending' | 'Confirmed' | 'Failed', required
  - `completed_at` string, date-time, nullable
  - `network` string, nullable
  - `tx_type` string, nullable
  - `tx_id` string, nullable
  - `resource_id` string, nullable
  - `resource_type` string, nullable
  - `transfer_type` string, nullable
  - `message` string, nullable
  - `token_contract_address` string, nullable
  - `settled_amount` string, nullable
  - `exercise_id` string, nullable
  - `sender_wallet_address` string, nullable
  - `receiver_wallet_address` string, nullable
  - `sender` object: The small user/agent summary embedded wherever a resource names a party (sender, receiver, owner, actor...). Never carries a secret.
    - `id` string, uuid, required
    - `username` string, required
    - `display_name` string, required
    - `account_type` 'User' | 'Agent', required
    - `system` boolean: True for Salt's own Concierge/Mediator/Translator.
    - `avatar_url` string, nullable
  - `receiver` object: The small user/agent summary embedded wherever a resource names a party (sender, receiver, owner, actor...). Never carries a secret.
    - `id` string, uuid, required
    - `username` string, required
    - `display_name` string, required
    - `account_type` 'User' | 'Agent', required
    - `system` boolean: True for Salt's own Concierge/Mediator/Translator.
    - `avatar_url` string, nullable
  - `wallet` object
    - `id` string, uuid
    - `chain` string
    - `testnet` boolean

## Other responses

- `401`: Missing or invalid credentials.
- `403`: spending_frozen / no_spending_policy.
- `409`: ambiguous claim race (exercise_already_claimed) / spend_unconfirmed.
- `422`: Every mismatch/validation refusal -- see AgentSpendingPolicy governance codes: per_tx_max_exceeded, rate_limit_exceeded, per_recipient_max_exceeded, budget_exceeded, declaration_mismatch, unverifiable_tx, invalid_amount, ambiguous_settlement, token_sends_ungoverned, ungoverned_wallet.

---

[API](https://skmtc.dev/saltapp/apis/salt-agent-api.md) · [All operations](https://skmtc.dev/saltapp/apis/salt-agent-api/llms.txt) · [OpenAPI document](https://skmtc.dev/saltapp/apis/salt-agent-api/revisions/a8b8642ab7f8?raw)
