Transactions
The lifecycle of a money movement — buy, sell, swap, withdraw, deposit.
A transaction represents any movement of value through Blacksheep.
Types
| Type | Direction | API |
|---|---|---|
deposit | External → Blacksheep balance | (incoming, no API call) |
withdraw | Blacksheep balance → external account | transaction.transfer |
buy | Fiat → crypto | transaction.transfer |
sell | Crypto → fiat | transaction.transfer |
swap | Currency A → currency B (both held) | transaction.transfer |
The type filter on transaction.getMany accepts all, buy, sell, withdraw, or deposit.
One endpoint, two workflows
transaction.transfer is the single entry point for every outgoing movement. What runs is
read off the payload shape, not off a mode flag:
currency_in | external_accounts.to | What happens |
|---|---|---|
| omitted | external account | Direct payout: the destination receives exactly currency_out, minus fees |
| set | your own bank account | Payout with delivery FX: the rail converts your stablecoin into currency_in |
| set | recipient / wallet / omitted | Conversion on the platform, then any external leg is paid out |
Omitting currency_in is the canonical "send X as X" shape; never repeat currency_out on
both sides, the request is rejected when the two codes match. Delivery FX requires a
stablecoin currency_out; a fiat or native-crypto source into your own bank is a
conversion, and is handled as one.
Lifecycle
Transactions progress through the following states:
PENDING— accepted and queuedCOMPLETED— settledFAILED— could not be completed (insufficient funds, rejected by counterparty, etc.)CANCELLED— cancelled before settlement
Listen for state transitions via Webhooks — polling transaction.get works but is wasteful.
Retries
Mutating endpoints do not accept a client idempotency key — the request schema is strict and rejects unknown fields. A retried transaction.transfer is a new transaction, so guard against duplicates on your side (e.g. don't resend until the first call returns a transaction id or errors). Each successful mutation returns its new transaction id; reconcile against that.
Reading transactions
transaction.get— fetch a single transaction byidtransaction.getMany— list, filterable bytype,search, andrecipient_id, with an optionallimit(max 100). Returns{ transactions, totals? }.