MolnPayDocs
API reference

Conversions

GET/v1/conversion/rules

One entry per network enabled for your project: whether it can convert at all (and why not), whether you switched it on, the target coin, the coins you keep as received, and the target choices — stablecoins first, then every other coin listed on that network.

Conversion happens on chain, from the treasury, after a payment is credited and swept: a payment is never delayed or refused because of it, and a conversion that cannot be executed leaves the payment in the coin it arrived in.

AuthorizationBearer <token>

Authorization: Bearer mp<64 hex> for live, mptest<64 hex> for test.

The token is the prefix plus 64 lowercase hex characters (32 CSPRNG bytes) and nothing else — no separators, no embedded fields — so nothing in it needs quoting, escaping or encoding. Send it in the Authorization header and nowhere else. Never put it in a query string: URLs reach access logs, proxy logs, browser history and Referer headers, and a key that lands in any of those is a leaked key. A key's KIND (checkout, payout or wallet) is a property of the key, not of the string: it is chosen at creation, returned by GET /v1/ping, and decides which routes the key may reach.

The full key is shown exactly once, at creation. No endpoint can return it afterwards. Moving funds additionally requires signing to be enabled globally, for your project, and for that key — so a read-only key is a supported configuration.

In: header

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

application/json

curl -X GET "https://example.com/v1/conversion/rules"
{  "object": "list",  "has_more": true,  "next_cursor": "string",  "data": [    {      "object": "conversion_rule",      "chain": "ethereum",      "name": "string",      "supported": true,      "unsupported_reason": "string",      "enabled": true,      "target_asset": "string",      "keep_assets": [        "string"      ],      "targets": [        {          "symbol": "string",          "stable": true,          "is_native": true,          "contract": "string"        }      ],      "updated_at": "2019-08-24T14:15:22Z"    }  ]}
PUT/v1/conversion/rules/{chain}

Takes effect on the NEXT payment; rows already queued keep the target they were given. Refused with conversion_unsupported_chain on a network that cannot convert, invalid_target when the target is not listed on the network, and invalid_keep_asset when a keep entry is not.

AuthorizationBearer <token>

Authorization: Bearer mp<64 hex> for live, mptest<64 hex> for test.

The token is the prefix plus 64 lowercase hex characters (32 CSPRNG bytes) and nothing else — no separators, no embedded fields — so nothing in it needs quoting, escaping or encoding. Send it in the Authorization header and nowhere else. Never put it in a query string: URLs reach access logs, proxy logs, browser history and Referer headers, and a key that lands in any of those is a leaked key. A key's KIND (checkout, payout or wallet) is a property of the key, not of the string: it is chosen at creation, returned by GET /v1/ping, and decides which routes the key may reach.

The full key is shown exactly once, at creation. No endpoint can return it afterwards. Moving funds additionally requires signing to be enabled globally, for your project, and for that key — so a read-only key is a supported configuration.

In: header

Path Parameters

chain*string

Value in

  • "ethereum"
  • "bsc"
  • "polygon"
  • "arbitrum"
  • "base"
  • "avalanche"
  • "tron"
  • "solana"
  • "ton"
  • "bitcoin"
  • "dogecoin"
  • "optimism"
  • "linea"
  • "zksync"
  • "scroll"

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

application/json

application/json

curl -X PUT "https://example.com/v1/conversion/rules/ethereum" \  -H "Content-Type: application/json" \  -d '{    "enabled": true,    "target_asset": "string"  }'
{  "object": "conversion_rule",  "chain": "ethereum",  "name": "string",  "supported": true,  "unsupported_reason": "string",  "enabled": true,  "target_asset": "string",  "keep_assets": [    "string"  ],  "targets": [    {      "symbol": "string",      "stable": true,      "is_native": true,      "contract": "string"    }  ],  "updated_at": "2019-08-24T14:15:22Z"}
GET/v1/conversions

One row per payment, written when the payment is credited: converted with the executed rate and this payment's share of the swap's measured output, skipped with the reason (the rule was off, the coin is kept, it already was the target…), queued while it waits, or failed when every attempt reverted — which leaves the payment in the coin it arrived in. Manual conversions (kind: manual) appear here too, one row per customer balance they drew on.

AuthorizationBearer <token>

Authorization: Bearer mp<64 hex> for live, mptest<64 hex> for test.

The token is the prefix plus 64 lowercase hex characters (32 CSPRNG bytes) and nothing else — no separators, no embedded fields — so nothing in it needs quoting, escaping or encoding. Send it in the Authorization header and nowhere else. Never put it in a query string: URLs reach access logs, proxy logs, browser history and Referer headers, and a key that lands in any of those is a leaked key. A key's KIND (checkout, payout or wallet) is a property of the key, not of the string: it is chosen at creation, returned by GET /v1/ping, and decides which routes the key may reach.

The full key is shown exactly once, at creation. No endpoint can return it afterwards. Moving funds additionally requires signing to be enabled globally, for your project, and for that key — so a read-only key is a supported configuration.

In: header

Query Parameters

limit?integer
Range1 <= value <= 100
Default25
cursor?string

Opaque cursor from the previous page's next_cursor.

status?string

Value in

  • "queued"
  • "converting"
  • "converted"
  • "skipped"
  • "failed"
chain?string

Value in

  • "ethereum"
  • "bsc"
  • "polygon"
  • "arbitrum"
  • "base"
  • "avalanche"
  • "tron"
  • "solana"
  • "ton"
  • "bitcoin"
  • "dogecoin"
  • "optimism"
  • "linea"
  • "zksync"
  • "scroll"
kind?string

Value in

  • "auto"
  • "manual"

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

curl -X GET "https://example.com/v1/conversions"
{  "object": "list",  "has_more": true,  "next_cursor": "string",  "data": [    {      "object": "conversion",      "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",      "kind": "auto",      "payment_id": "d43b87f9-9e28-4802-8eaa-6ee91a40ea71",      "receipt_no": "string",      "chain": "ethereum",      "from_asset": "string",      "to_asset": "string",      "amount_in": "1500000000000000000",      "amount_in_decimal": "string",      "amount_out": "string",      "amount_out_decimal": "string",      "rate": "string",      "status": "queued",      "reason": "off",      "batch_id": "4da22c97-b7d5-4e31-8c3a-03870ebc7b20",      "tx_hash": "string",      "explorer_url": "string",      "attempts": 0,      "created_at": "2019-08-24T14:15:22Z",      "updated_at": "2019-08-24T14:15:22Z",      "settled_at": "2019-08-24T14:15:22Z"    }  ]}
POST/v1/conversions

The same on-chain pipeline auto conversion uses, entered by hand: the amount is drawn from the customer balances that hold the coin, sized against what your treasury holds free of everything already in flight, and the swap is quoted and planned at once. Quote first with POST /v1/conversions/quote.

Refused with 402 insufficient_funds when the treasury on that network does not hold the amount (coins still in deposit addresses are swept first; available on the quote says what can go now), 422 conversion_unsupported_chain on a network with no route, 422 conversion_test_mode on a test-mode project, 503 conversion_unavailable when conversion is not configured.

Returns 202 with the rows and, when it could be planned immediately, the batch. Follow the batch on GET /v1/conversions/batches/{id}; conversion.completed fires per row when it settles. Your plan's swap rate is charged on settlement.

Idempotency-Key is REQUIRED: a retry with the same key replays the first answer rather than converting twice.

AuthorizationBearer <token>

Authorization: Bearer mp<64 hex> for live, mptest<64 hex> for test.

The token is the prefix plus 64 lowercase hex characters (32 CSPRNG bytes) and nothing else — no separators, no embedded fields — so nothing in it needs quoting, escaping or encoding. Send it in the Authorization header and nowhere else. Never put it in a query string: URLs reach access logs, proxy logs, browser history and Referer headers, and a key that lands in any of those is a leaked key. A key's KIND (checkout, payout or wallet) is a property of the key, not of the string: it is chosen at creation, returned by GET /v1/ping, and decides which routes the key may reach.

The full key is shown exactly once, at creation. No endpoint can return it afterwards. Moving funds additionally requires signing to be enabled globally, for your project, and for that key — so a read-only key is a supported configuration.

In: header

Header Parameters

Idempotency-Key*string

REQUIRED. A retry without one can send funds twice, so the request is rejected outright.

Lengthlength <= 255

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

application/json

application/json

curl -X POST "https://example.com/v1/conversions" \  -H "Idempotency-Key: string" \  -H "Content-Type: application/json" \  -d '{    "chain": "ethereum",    "from_asset": "string",    "to_asset": "string",    "amount": "string"  }'
{  "object": "conversion_request",  "rows": [    {      "object": "conversion",      "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",      "kind": "auto",      "payment_id": "d43b87f9-9e28-4802-8eaa-6ee91a40ea71",      "receipt_no": "string",      "chain": "ethereum",      "from_asset": "string",      "to_asset": "string",      "amount_in": "1500000000000000000",      "amount_in_decimal": "string",      "amount_out": "string",      "amount_out_decimal": "string",      "rate": "string",      "status": "queued",      "reason": "off",      "batch_id": "4da22c97-b7d5-4e31-8c3a-03870ebc7b20",      "tx_hash": "string",      "explorer_url": "string",      "attempts": 0,      "created_at": "2019-08-24T14:15:22Z",      "updated_at": "2019-08-24T14:15:22Z",      "settled_at": "2019-08-24T14:15:22Z"    }  ],  "batch": {    "object": "conversion_batch",    "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",    "chain": "ethereum",    "from_asset": "string",    "to_asset": "string",    "amount_in": "1500000000000000000",    "amount_in_decimal": "string",    "amount_out": "string",    "amount_out_decimal": "string",    "expected_out": "string",    "expected_out_decimal": "string",    "min_out": "string",    "rate": "string",    "amount_usd": "string",    "fee_cents": 0,    "market": "string",    "status": "approving",    "error_code": "string",    "approve_tx_hash": "string",    "approve_explorer_url": "string",    "swap_tx_hash": "string",    "swap_explorer_url": "string",    "rows": 0,    "created_at": "2019-08-24T14:15:22Z",    "updated_at": "2019-08-24T14:15:22Z",    "settled_at": "2019-08-24T14:15:22Z"  },  "pending_reason": "string"}
POST/v1/conversions/quote

Read-only. One route quote, the estimated gas, the fee your plan would charge, and how much of the coin your treasury can convert right now. Quotes are not held: the batch quotes again when it is planned, and the swap books what the chain actually delivers.

AuthorizationBearer <token>

Authorization: Bearer mp<64 hex> for live, mptest<64 hex> for test.

The token is the prefix plus 64 lowercase hex characters (32 CSPRNG bytes) and nothing else — no separators, no embedded fields — so nothing in it needs quoting, escaping or encoding. Send it in the Authorization header and nowhere else. Never put it in a query string: URLs reach access logs, proxy logs, browser history and Referer headers, and a key that lands in any of those is a leaked key. A key's KIND (checkout, payout or wallet) is a property of the key, not of the string: it is chosen at creation, returned by GET /v1/ping, and decides which routes the key may reach.

The full key is shown exactly once, at creation. No endpoint can return it afterwards. Moving funds additionally requires signing to be enabled globally, for your project, and for that key — so a read-only key is a supported configuration.

In: header

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

application/json

curl -X POST "https://example.com/v1/conversions/quote" \  -H "Content-Type: application/json" \  -d '{    "chain": "ethereum",    "from_asset": "string",    "to_asset": "string",    "amount": "string"  }'
{  "object": "conversion_quote",  "chain": "ethereum",  "from_asset": "string",  "to_asset": "string",  "amount_in": "1500000000000000000",  "amount_in_decimal": "string",  "expected_out": "1500000000000000000",  "expected_out_decimal": "string",  "min_out": "1500000000000000000",  "min_out_decimal": "string",  "slippage_bps": 0,  "rate": "string",  "amount_usd": "string",  "gas_usd": "string",  "fee_cents": 0,  "market": "string",  "available": "1500000000000000000",  "available_decimal": "string",  "needs_approval": true}
GET/v1/conversions/batches/{id}
AuthorizationBearer <token>

Authorization: Bearer mp<64 hex> for live, mptest<64 hex> for test.

The token is the prefix plus 64 lowercase hex characters (32 CSPRNG bytes) and nothing else — no separators, no embedded fields — so nothing in it needs quoting, escaping or encoding. Send it in the Authorization header and nowhere else. Never put it in a query string: URLs reach access logs, proxy logs, browser history and Referer headers, and a key that lands in any of those is a leaked key. A key's KIND (checkout, payout or wallet) is a property of the key, not of the string: it is chosen at creation, returned by GET /v1/ping, and decides which routes the key may reach.

The full key is shown exactly once, at creation. No endpoint can return it afterwards. Moving funds additionally requires signing to be enabled globally, for your project, and for that key — so a read-only key is a supported configuration.

In: header

Path Parameters

id*string
Formatuuid

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

application/json

curl -X GET "https://example.com/v1/conversions/batches/497f6eca-6276-4993-bfeb-53cbbbba6f08"
{  "object": "conversion_batch",  "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",  "chain": "ethereum",  "from_asset": "string",  "to_asset": "string",  "amount_in": "1500000000000000000",  "amount_in_decimal": "string",  "amount_out": "string",  "amount_out_decimal": "string",  "expected_out": "string",  "expected_out_decimal": "string",  "min_out": "string",  "rate": "string",  "amount_usd": "string",  "fee_cents": 0,  "market": "string",  "status": "approving",  "error_code": "string",  "approve_tx_hash": "string",  "approve_explorer_url": "string",  "swap_tx_hash": "string",  "swap_explorer_url": "string",  "rows": 0,  "created_at": "2019-08-24T14:15:22Z",  "updated_at": "2019-08-24T14:15:22Z",  "settled_at": "2019-08-24T14:15:22Z"}
GET/v1/conversions/{id}
AuthorizationBearer <token>

Authorization: Bearer mp<64 hex> for live, mptest<64 hex> for test.

The token is the prefix plus 64 lowercase hex characters (32 CSPRNG bytes) and nothing else — no separators, no embedded fields — so nothing in it needs quoting, escaping or encoding. Send it in the Authorization header and nowhere else. Never put it in a query string: URLs reach access logs, proxy logs, browser history and Referer headers, and a key that lands in any of those is a leaked key. A key's KIND (checkout, payout or wallet) is a property of the key, not of the string: it is chosen at creation, returned by GET /v1/ping, and decides which routes the key may reach.

The full key is shown exactly once, at creation. No endpoint can return it afterwards. Moving funds additionally requires signing to be enabled globally, for your project, and for that key — so a read-only key is a supported configuration.

In: header

Path Parameters

id*string
Formatuuid

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

application/json

curl -X GET "https://example.com/v1/conversions/497f6eca-6276-4993-bfeb-53cbbbba6f08"
{  "object": "conversion",  "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",  "kind": "auto",  "payment_id": "d43b87f9-9e28-4802-8eaa-6ee91a40ea71",  "receipt_no": "string",  "chain": "ethereum",  "from_asset": "string",  "to_asset": "string",  "amount_in": "1500000000000000000",  "amount_in_decimal": "string",  "amount_out": "string",  "amount_out_decimal": "string",  "rate": "string",  "status": "queued",  "reason": "off",  "batch_id": "4da22c97-b7d5-4e31-8c3a-03870ebc7b20",  "tx_hash": "string",  "explorer_url": "string",  "attempts": 0,  "created_at": "2019-08-24T14:15:22Z",  "updated_at": "2019-08-24T14:15:22Z",  "settled_at": "2019-08-24T14:15:22Z"}