Endpoint
Request a conversion
/v1/conversionsRequests a conversion of one of your balances into another asset or network, wallet to wallet, through the venue you chose from the offers. Nothing is converted until an Owner or Finance member approves it in the dashboard with a passkey; the offer is quoted again then, and the conversion is refused if the fresh output is below its minimum. The answer is 202 with the conversion awaiting_approval. See money out.
- Scope a restricted key needs
conversions:write- Publishable key
- Not allowed: secret or restricted key only
- Idempotency-Key
- Required. A request without it is refused.
Parameters
| Parameter | Type and place | Meaning |
|---|---|---|
Orrerie-Version | stringheader | API version date. Default: the version the key was created with. Example 2026-10-11. |
Idempotency-Keyrequired | stringheader | Required here: a person at your business approves what this request asks for (money out, or a new saved address), and a retry with the same key never asks for it twice. 1 to 255 characters. |
Request body
A JSON object. The body is required. A field the call does not list is refused with parameter_unknown.
| Field | Type | Meaning |
|---|---|---|
fromrequired | object | {asset, amount}; amount may be max. |
to_assetrequired | string | The asset id to convert into, as in the offer you chose. |
venuerequired | string | The venue you chose from the offers. One of relay, kyberswap, thorchain, sideshift, rubic, across. |
max_slippage_bps | integer | 10 to 300 (0.1% to 3%). Default 50. KyberSwap accepts at most 50. |
metadata | object | Your own key-value data (rules in Metadata). |
Example request
curl
curl https://api.orrerie.com/v1/conversions \
-H "Authorization: Bearer $ORRERIE_SECRET_KEY" \
-H "Idempotency-Key: 8f14e45f-ceea-467f-a9d2-6f1c2b3d4e5a" \
-H "Content-Type: application/json" \
-d '{
"from": {
"asset": "bitcoin:btc",
"amount": "0.01"
},
"to_asset": "base:usdc",
"venue": "relay"
}'JavaScript
const response = await fetch("https://api.orrerie.com/v1/conversions", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.ORRERIE_SECRET_KEY}`,
"Idempotency-Key": "8f14e45f-ceea-467f-a9d2-6f1c2b3d4e5a",
"Content-Type": "application/json",
},
body: JSON.stringify({
"from": {
"asset": "bitcoin:btc",
"amount": "0.01"
},
"to_asset": "base:usdc",
"venue": "relay"
}),
});
const result = await response.json();
if (!response.ok) throw new Error(`${result.error.code}: ${result.error.message}`);
console.log(result);Python
import os
import requests
response = requests.post(
"https://api.orrerie.com/v1/conversions",
headers={"Authorization": f"Bearer {os.environ['ORRERIE_SECRET_KEY']}", "Idempotency-Key": "8f14e45f-ceea-467f-a9d2-6f1c2b3d4e5a"},
json={
"from": {
"asset": "bitcoin:btc",
"amount": "0.01",
},
"to_asset": "base:usdc",
"venue": "relay",
},
timeout=30,
)
result = response.json()
if not response.ok:
raise RuntimeError(f"{result['error']['code']}: {result['error']['message']}")
print(result)PHP
<?php
$request = curl_init('https://api.orrerie.com/v1/conversions');
curl_setopt_array($request, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('ORRERIE_SECRET_KEY'),
'Idempotency-Key: 8f14e45f-ceea-467f-a9d2-6f1c2b3d4e5a',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'from' => [
'asset' => 'bitcoin:btc',
'amount' => '0.01',
],
'to_asset' => 'base:usdc',
'venue' => 'relay',
]),
]);
$body = curl_exec($request);
if ($body === false) {
throw new RuntimeException(curl_error($request));
}
$result = json_decode($body, true);
if (curl_getinfo($request, CURLINFO_HTTP_CODE) >= 400) {
throw new RuntimeException($result['error']['code'] . ': ' . $result['error']['message']);
}
print_r($result);Responses
202 Accepted
The request was accepted and is waiting: for a person to approve it in the dashboard, or to be built in the background. Nothing has been signed or sent. The answer is the conversion object. Headers: Orrerie-Request-Id.
Example response, 202
{
"id": "cv_ban2ezvpwf4j4d09h4htv42j",
"object": "conversion",
"livemode": true,
"created": "2026-10-12T11:00:30.000Z",
"updated": "2026-10-12T11:00:30.000Z",
"status": "awaiting_approval",
"pending_reason": null,
"venue": "relay",
"venue_progress": null,
"from": {
"wallet": "wal_zjdztygt4g73zm0cdcjjf43k",
"asset": "bitcoin:btc",
"amount": "0.01000000"
},
"to": {
"wallet": "wal_bsfw07hymawmda7gg8jsyy3g",
"asset": "base:usdc",
"amount_estimated": "1168.420000",
"amount_minimum": "1162.577900",
"amount_received": null
},
"rate": "116842.00",
"max_slippage_bps": 50,
"fees": [
{
"kind": "route_fee",
"amount": "1.38",
"currency": "USD"
},
{
"kind": "network_fee",
"amount": "0.61",
"currency": "USD"
}
],
"in_transit_notice": "While a conversion is being routed it is held by Relay, a separate company. Orrerie never holds it.",
"requested_by": {
"type": "api_key",
"id": "key_6e3gg2c6ea176xxdek2nar6v"
},
"approved_by": null,
"approval_url": "https://merchant.orrerie.com/approve/cv_ban2ezvpwf4j4d09h4htv42j",
"approval_expires_at": "2026-10-19T11:00:30.000Z",
"send_transaction_hash": null,
"receive_transaction_hash": null,
"failure_code": null,
"cancellation_reason": null,
"approved_at": null,
"sent_at": null,
"confirmed_at": null,
"metadata": {}
}Any other status: an error
A status of 400 or above answers with the error object. Branch on its code, never on its message.
Errors
Beside the errors every call can answer with (a bad key, a missing scope, the rate limit), this call answers with:
| Code | HTTP | Meaning |
|---|---|---|
idempotency_key_required | 400 | The endpoint moves money on approval (refunds, payouts, batches, conversions, saved addresses) and needs an Idempotency-Key. |
conversion_no_route | 409 | The chosen venue has no route for this pair or amount now. error.offers_url lists what every venue says. |
insufficient_balance | 409 | The available balance (amount minus reserved) of the source asset is too low; error.available gives it. |
fee_account_low | 409 | The fee account cannot pay the network fee. error.needed says how much of which coin on which network must be held, for example {"asset": "tron:. |
rail_unavailable | 503 | The rail cannot be used now. error.reason is the exact refusal: relay_unavailable, relay_no_route, relay_amount_too_low, relay_low_liquidity, relay_paused, route_fee_over_cap, provider_route_mismatch, provider_, refund_, recipient_not_attested, or asset_not_covered; error.available_assets lists what can be used instead. Nothing was created at the provider and nothing was switched. |
merchant_restricted | 403 | The merchant is restricted: new orders, payouts to others and conversions are off. Reads and withdrawals to saved addresses work. |
wallet_needs_review | 409 | The wallet holds less than Orrerie's records show, because money left it that nothing recorded. Money out from it waits until an Owner has reviewed the wallet in the dashboard. |
balance_changed | 409 | The balance moved after the amount was worked out, so the amount no longer holds. Ask again for a fresh one. |