# Send money to a payee, a wallet or an address

`POST /payouts` · Skerry · Paying out

Send money to a payee, a wallet or an address. Needs an Idempotency-Key. `amount` is a decimal string in `from.currency`; `amount_minor` is the same amount as integer minor units, and either may be sent. A bank payout may name a `rail` or a `speed` (fastest, cheapest, standard); otherwise the rail is chosen and returned with the reason. `quote_id` executes exactly what was quoted. `execute_at`, `schedule` or `release_on` create a scheduled payout instead of sending now. An outside address is checked for its chain's format and for the coin being on that chain (Base when no chain is named). `travel_rule` carries originator and beneficiary details for an outside address; it is passed on and not kept. The answer carries `amount_minor`, `fee_minor` and `authorisation`.

- Scope: payouts:write
- Moves money: yes
- Idempotency: required
- Untrusted: reference, external_ref, remittance, hold.reason

## Parameters

- `Idempotency-Key` (header, required), string: A repeat with the same key and body returns the first answer instead of acting twice.

## Request body

`application/json`

```json
{
  "type": "object",
  "required": [
    "customer_id",
    "from",
    "to"
  ],
  "properties": {
    "customer_id": {
      "type": "string",
      "maxLength": 200
    },
    "amount": {
      "type": "string",
      "pattern": "^\\d{1,18}(\\.\\d{1,10})?$",
      "description": "The amount as a decimal string in `from.currency`. Send this or `amount_minor`."
    },
    "amount_minor": {
      "type": "integer",
      "minimum": 1,
      "description": "The same amount in integer minor units of `from.currency`."
    },
    "from": {
      "type": "object",
      "required": [
        "currency",
        "wallet_id"
      ],
      "properties": {
        "currency": {
          "type": "string",
          "description": "A lowercase currency code or stablecoin ticker."
        },
        "wallet_id": {
          "type": "string",
          "maxLength": 200
        }
      }
    },
    "to": {
      "type": "object",
      "required": [
        "currency"
      ],
      "properties": {
        "currency": {
          "type": "string",
          "description": "A lowercase currency code or stablecoin ticker."
        },
        "payee_id": {
          "type": "string",
          "maxLength": 200
        },
        "wallet_id": {
          "type": "string",
          "maxLength": 200
        },
        "address": {
          "type": "string",
          "maxLength": 200
        },
        "chain": {
          "type": "string",
          "maxLength": 40
        }
      },
      "description": "Exactly one of `payee_id`, `wallet_id` or `address`."
    },
    "rail": {
      "type": "string",
      "maxLength": 40
    },
    "speed": {
      "type": "string",
      "enum": [
        "fastest",
        "cheapest",
        "standard"
      ]
    },
    "quote_id": {
      "type": "string",
      "maxLength": 200,
      "description": "Executes exactly what was quoted, once."
    },
    "execute_at": {
      "type": "string",
      "format": "date-time"
    },
    "schedule": {
      "type": "object",
      "required": [
        "every",
        "unit"
      ],
      "properties": {
        "every": {
          "type": "integer",
          "minimum": 1
        },
        "unit": {
          "type": "string",
          "enum": [
            "day",
            "week",
            "month"
          ]
        },
        "end_at": {
          "type": "string",
          "format": "date-time"
        },
        "count": {
          "type": "integer",
          "minimum": 1
        }
      }
    },
    "release_on": {
      "oneOf": [
        {
          "type": "string",
          "enum": [
            "approval"
          ]
        },
        {
          "type": "object",
          "required": [
            "event",
            "object_id"
          ],
          "properties": {
            "event": {
              "type": "string",
              "maxLength": 200
            },
            "object_id": {
              "type": "string",
              "maxLength": 200
            }
          }
        }
      ]
    },
    "expires_at": {
      "type": "string",
      "format": "date-time"
    },
    "travel_rule": {
      "type": "object",
      "properties": {
        "originator": {
          "type": "object"
        },
        "beneficiary": {
          "type": "object"
        }
      }
    },
    "reference": {
      "type": "string",
      "maxLength": 500
    },
    "external_ref": {
      "type": "string",
      "maxLength": 200,
      "description": "The document this belongs to in your own system."
    },
    "external_kind": {
      "type": "string",
      "enum": [
        "invoice",
        "bill",
        "order",
        "booking",
        "other"
      ]
    },
    "remittance": {
      "type": "object",
      "properties": {
        "invoice_number": {
          "type": "string",
          "maxLength": 200
        },
        "amount": {
          "type": "string",
          "maxLength": 40
        },
        "date": {
          "type": "string",
          "maxLength": 40
        }
      }
    },
    "dry_run": {
      "type": "boolean",
      "description": "Check the request and report what would happen, without doing it."
    }
  }
}
```

## Responses

- `200`: Success.
- `202`: requires_approval — Not an error: the operation is held for a person. The body names the approval.
- `400`: price_below_minimum — The price is below the smallest single payment for a method (`detail.method`, `detail.minimum`), or has a part of a cent. Set `credit_only`, raise the price, or drop the method.
- `401`: dpop_invalid — The token is bound to a key and the DPoP proof was missing, wrong for this request, or already used.
- `402`: payment_failed — The payer's bank or card refused. `detail.reason` says why in plain terms.
- `403`: agent_payment_over_max — The merchant asks for more than `max_amount`. Nothing was signed. `detail.asked_minor` is the lowest price asked, in US cents.
- `404`: not_found — No such object in this project — including one that belongs to somebody else.
- `409`: token_not_issued — A delegated payment token could not be issued ready to use, for instance because the payer would have to act. Nothing was sent to the merchant.
- `429`: too_many_waiters — This key already has as many requests waiting (`?wait=`) as it may. Let one finish, or read without wait.
- `500`: internal_error — Ours. Quote the `request_id` and we can find the call.
- `502`: platform_error — A provider failed. Safe to retry with the same Idempotency-Key.
- `503`: oauth_unavailable — The authorisation server's keys could not be read, so tokens cannot be checked. API keys still work.

## Example

```sh
curl -X POST 'https://api.skerry.xyz/payouts' \
  -H 'Authorization: Bearer $KEY' \
  -H 'Content-Type: application/json' \
  -d '"{ customer_id, amount | amount_minor, from: { currency, wallet_id }, to: { currency, payee_id | wallet_id | address, chain? }, rail?, speed?, quote_id?, execute_at? | schedule?: { every, unit: day|week|month, end_at? | count? } | release_on?: { event, object_id } | \"approval\", expires_at?, travel_rule?: { originator, beneficiary }, reference?, external_ref?, external_kind?, remittance?: { invoice_number?, amount?, date? }, dry_run? }"'
```
