Exchange API
A crypto-to-crypto swap API you can call without an API key, an account, or a signup form. Quote a pair, create the order, poll its status. The same endpoints the SwapSS site itself runs on.
https://swapss.lol/api/v1
What you earn
A key is optional for trading and mandatory for earning: it is what attributes an order to you. The terms below are granted at signup, in full, without a call.
- Free to use. No setup fee, no monthly fee, no volume commitment.
- You earn 30% of our own service fee on every order you send, whatever you charge your users. Elsewhere an affiliate earns only what they add on top, so passing the raw rate through earns them nothing. Here it does not work that way.
- Setting your own markup on top of our rate is not open yet — the pricing path that would carry it is not finished. We would rather say so than hand you a control that charges your users nothing and pays you nothing. Your 30% is unaffected and is paid on every order today.
- Your users stay yours. We never contact them, never market to them and never put our name in front of them.
- No minimum payout. The common floor in this market is 300 USDT; ours is none.
- The network fee is passed through at cost and shown before you confirm. We never take a percentage of it.
- No business verification to get a key, to earn, or to withdraw.
The honest part, stated plainly rather than buried: your share is paid out of the service fee actually recorded on that order, and it becomes withdrawable once that fee has been collected. It is tied to a real accrual, not to a timer — an order that never settles never accrues, and we would rather say so here than have you find out from a balance that does not move.
A worked example
A $1,000 order at our 0.5% service fee, with our raw rate passed straight through to your users. Everywhere else that is the case where an affiliate is paid nothing at all.
| Line | With SwapSS | Typical elsewhere |
|---|---|---|
| Order size | $1,000.00 | $1,000.00 |
| What your users pay on top | nothing | nothing |
| Our service fee, 0.5% | $5.00 | $5.00 |
| Your share of it, 30% | $1.50 | $0.00 |
| You receive | $1.50 | $0.00 |
Those figures are the ones the accounting code computes, not a marketing rounding: the split is integer arithmetic on the order commission and a test pins these exact numbers.
Start in three steps
Nothing here needs a sales conversation, and none of it has to be redone when you go live.
- Join Open your API cabinet and join the programme. It takes one click, applies immediately, and puts you in sandbox with your share of the fee already granted.
- Create a sandbox key Give it a label, keep the default scopes, optionally fence it to your server IPs. The secret is shown exactly once — we only store a one-way digest of it, so there is nothing to look up later.
- Send your first quote Same endpoints as the rest of this page; the key just attributes the call to you. Live access is opened by a person once you are ready, and your sandbox integration carries over unchanged.
First authenticated request
curl -X POST https://swapss.lol/api/v1/quote \
-H 'authorization: Bearer ssx_sec_test_YOUR_KEY' \
-H 'content-type: application/json' \
-d '{
"fromChain": "ethereum",
"fromAsset": "USDT",
"toChain": "monero",
"toAsset": "XMR",
"amount": "500",
"rateType": "float"
}' Open your API cabinet You will be asked to sign in first.
Endpoints
| Method | Path | What it returns |
|---|---|---|
| GET | /health | Liveness. Use it as the availability check before offering a swap. |
| GET | /assets | Every asset with its chain, decimals, whether it can be a source, a destination, or both, and a wide per-asset bound. That bound is not the trading minimum: the amount a swap accepts depends on the pair, and the authoritative range comes back with the quote. |
| GET | /networks?scope=live | Live networks with block time, required confirmations and explorer base URL — enough to show an honest wait estimate before a deposit. |
| GET | /pairs?from_chain=&from_asset= | Every destination reachable from one source asset. Ask this instead of assuming a pair exists. |
| GET | /indicative?amount= | ?amount_to= | Display-only rate for a pair, cached briefly. Pass amount to estimate the output, or amount_to to estimate the input needed — both directions work on every pair here, because it is arithmetic on the cached rate rather than a fresh call. Carries no quote token and cannot create an order: use it to fill a rate field, never to settle one. |
| GET | /availability | Whether we are accepting exchanges right now, which rate types are open, and whether one pair is servable. Not /health: that reports the process is alive, which stays true while intake is paused. |
| POST | /quote | A binding quote: amounts, fees, limits, the refund-address policy for that route, and an expiry. Returns a quoteId the order call must use. |
| POST | /orders | Creates the order from a live quoteId. The server never recomputes amounts from your fields — an expired or unknown quote is refused rather than re-priced. |
| GET | /reports/orders | The orders your API key created, newest first, cursor-paginated, with expected and actual amounts kept separate. The one endpoint that requires a key: it is how you reconcile without polling every order. |
| GET | /orders/{publicId}?token= | Order status, timeline, confirmation progress and transaction links. The token is issued when the order is created. |
Quoting a pair
A quote is the only thing an order can be built from. It carries the amounts, the limits, the refund-address policy for that route, and an expiry — order creation binds the quoteId and refuses to re-price from client fields.
Request
curl -X POST https://swapss.lol/api/v1/quote \
-H 'content-type: application/json' \
-d '{
"fromChain": "bitcoin",
"fromAsset": "BTC",
"toChain": "monero",
"toAsset": "XMR",
"amount": "0.01",
"rateType": "float"
}' Response
{
"quoteId": "qt_Eq-_r6he8u5SLNur7yffJcc5ibP-9T0igoOyVcW1xl8",
"rateType": "float",
"from": { "chain": "bitcoin", "asset": "BTC", "amount": "0.01" },
"to": { "chain": "monero", "asset": "XMR", "amount": "1.72765483" },
"fees": {
"serviceFee": "0", "serviceFeeAsset": "BTC", "serviceFeeBps": 0,
"networkFee": "0", "networkFeeAsset": "BTC",
"exchangeFee": "0", "exchangeFeeAsset": "USD"
},
"limits": { "min": "0.0001", "max": "6.814" },
"expiresAt": "2026-07-24T19:44:28Z",
"warnings": ["Final amount is determined after deposit confirmations"],
"exchangePreview": { "label": "SwapSS", "priceImpactBps": 0, "etaSeconds": 1800 },
"startMethod": "deposit",
"requiresConnectedWallet": false,
"sourceAddressRequired": false,
"requiresRefundAddress": false,
"refundAddressPolicy": "optional",
"requiresRecipientMemo": false,
"requiresRefundMemo": false,
"supportsRecipientMemo": false,
"supportsRefundMemo": false
}Knowing the wait before the deposit
The network registry reports block time and required confirmations per chain, so an integration can state the real wait instead of a generic "a few minutes". Bitcoin below is 3 confirmations at a 600-second block time — about 30 minutes.
{
"id": "bitcoin",
"name": "Bitcoin",
"nativeCurrency": "BTC",
"blockTimeSeconds": 600,
"confirmationsRequired": 3,
"explorerUrl": "https://mempool.space",
"status": "active",
"chainType": "utxo"
}Rates and fees
Two rate types, and the current values are always readable from GET /fees rather than hardcoded:
- Floating — 0.5%. The final amount settles at the rate when the deposit confirms.
- Fixed — 1%. The amount is locked when the order is created; the order carries the deadline by which the deposit must arrive.
- The network fee is quoted before confirmation. Nothing is deducted that a quote did not show.
What the integration is responsible for
- Treat every amount as a decimal string. Amounts are integers in minor units internally and are never floats on any money path.
- Never assume a pair exists: read it from /pairs, and let a 422 disable that direction rather than retry it.
- Order statuses are one fixed vocabulary — waiting_deposit, confirming_deposit, checking, exchanging, sending, completed, action_required, review, refunding, refunded, expired, cancelled, failed. Internal state names are never exposed. Treat a status you do not recognise as non-terminal and keep polling: new ones are added additively and an unknown one never means the order is over.
- review is not a failure. It means the order needs attention before it continues — an automatic retry or an operator check — and telling a user their funds are lost there is the worst thing an integration can do. A refund is neither automatic nor instant, so do not promise your users a refund window; the one that binds us is in the Terms.
- A quote expires. Re-quote instead of holding one; order creation on an expired quote is refused, not silently re-priced.
- Show chain, asset and address together wherever a user can copy or confirm. A correct address on the wrong chain loses the funds.
Limits and failure
- Endpoints are rate limited per family; a 429 carries a retry hint and is not a reason to fail the swap.
- 503 means the pair cannot be served right now. Fail closed and hide the direction — an exchange that quotes what it cannot execute is worse than one that says no.
- Errors are JSON with a human-readable message and never leak internals.
- Every error carries a stable code beside that message: INVALID_PARAMETER, AMOUNT_BELOW_MINIMUM, AMOUNT_ABOVE_MAXIMUM, AMOUNT_OUTSIDE_LIMITS, PAIR_UNAVAILABLE, RATE_LIMITED, UPSTREAM_UNAVAILABLE, INTERNAL_ERROR, REQUEST_REJECTED. Branch on the code, show the message. Once a code is published it is never renamed or given a new meaning — new situations get new codes — so mapping them into your own states is safe to do once.
- An amount rejection hands you the bounds as data, not only inside the sentence: limits.min, limits.max and limits.asset, always expressed in the source asset. AMOUNT_OUTSIDE_LIMITS rather than a specific edge means the side genuinely could not be determined — a reverse quote prices the destination while the bounds are source-side — so show the range instead of telling the user which way to move.
- limits.destination repeats those bounds in the destination asset, for the case where the user priced that side. It is marked estimated because it comes from a recently cached rate, and it is absent rather than stale when no rate is known. The minimum rounds up and the maximum rounds down, so acting on either edge cannot land you outside the real range.
- A 400 means we could not read the request; a 200 carrying available:false means we read it and cannot serve that pair. They are different answers on purpose — a misspelled parameter used to look like a permanently dead pair. A 400 names the parameter and carries a code.
- Query parameters are accepted in both snake_case and camelCase, so from_chain and fromChain both work.
- A chain can be named either by our id (ethereum, base, tron) or, for EVM chains, by the EIP-155 number your wallet already carries (1, 8453, 137). /availability echoes back the resolved id, which is the fastest way to learn the spelling the quote request wants.
- Indicative amounts are estimated from the cached rate, not from a fresh call, so you can ask on every keystroke without being rate limited. They are a preview: only a quote binds a number, and amountWithinLimits tells you whether the trade would be accepted before you ask for one.
- On an indicative response, available is always true and maxFrom is an empty string when the pair has no declared ceiling — unbounded, not zero. A pair we cannot serve answers available:false instead, so one field decides it either way.
Wallets and aggregators
If you are integrating SwapSS into a wallet, a rate comparison site, or a swap widget, get in touch before you start. We will confirm the pair coverage you need, raise the rate limits for your traffic, and answer route questions directly rather than through a form.
Integration questions: @swappsy
Questions integrators ask first
Do I need an API key or an account?
- Not to trade. Quoting and order creation are unauthenticated, and reading an order back requires the token issued when that order was created, so an order id alone never exposes someone else’s swap. A key is optional: it attributes the orders it creates, lets you read them back without holding each token, and is the only way to reach the reports endpoint.
Is there a sandbox?
- Not in the sense of play money, and this is worth reading twice. Your first key is labelled sandbox, but it talks to the same exchange a live key does: a quote is a real quote, and an order you create is a real order that waits for a real deposit. What the label changes is the rate limit, which is lower, and that what you earn stays pending until a person opens live access. Read endpoints and quotes create nothing, so you can build the whole integration without moving funds — just never point a test suite at order creation expecting fake money to come back.
Do I have to poll for status, or can you call me?
- We call you. Register an endpoint in your cabinet and you get an order-status callback signed with a secret shown to you once, carrying the event id, the event type and a delivery id. Failures are retried six times with a widening gap, every attempt is listed in the cabinet with its response code, and a delivery left hanging by a restart is picked back up rather than lost. Polling still works if you prefer it.
Which assets are supported?
- Read GET /assets rather than trusting a list on a page. As of this writing 20 networks are live, including Monero and Zcash in both directions.
What happens if a deposit arrives late or in the wrong amount?
- The order is not silently dropped. A late or partial deposit on a fixed rate moves to the floating rate at confirmation time, and anything genuinely ambiguous goes to human review with the funds preserved rather than to an automatic guess.
Can I list SwapSS rates in an aggregator?
- Yes. Indicative rates are display-only, cached briefly, and carry no quote token, which makes them the right feed for a comparison table. Message us before you build so we can size the rate limits for your traffic.
What does it cost to integrate?
- Nothing. There is no setup fee, no monthly fee and no volume commitment, and there is no minimum you have to reach before you can withdraw what you have earned. The network fee on a payout is passed through at cost.
How can I earn if I charge my users nothing extra?
- Because your share is a share of our service fee, not a slice of something you added on top. Your users get our raw rate and you still earn 30% of the fee on every order you send. A programme that only pays you a cut of your own markup pays you nothing in that case.
Do I have to verify my business to get a key?
- No. Enrolling is self-serve and immediate, and it needs no company documents to get a key, to earn, or to withdraw. You start in sandbox — real endpoints, no real money — and a person opens live access when you are ready.