🔑 Authentication & base URL
Everything you need to make your first successful call, and the four things that trip up most integrations.
Base URL
https://settla.net
There is one environment. There is no sandbox and no testnet — every endpoint talks to a mainnet node, so treat read calls as free and write calls as real.
Every path in this reference is absolute and already includes the prefix:
| Prefix | What it talks to |
|---|---|
/api/v1/btc/… | Bitcoin Core node |
/api/v1/eth/… | Ethereum (Erigon) node |
/api/v1/trx/… | java-tron node, plus Settla's own Tron indexer |
/api/v1/webhooks… | Settla itself — no coin segment, webhooks are shared across all coins |
Getting a key
Create one in the dashboard at settla.net/app/keys. The key is shown once, at creation. It is a 40-character alphanumeric string:
UgyARw47HVR7WyXHqFsDJOQlIPHieCngwTkBEZdb
A key is bound to your account, not to a coin — the same key works for /btc, /eth, /trx and /webhooks. Deactivating a key in the dashboard takes effect on the next request.
Sending the key
Put it in the X-API-Key header. Header names are case-insensitive, so x-api-key works identically.
curl 'https://settla.net/api/v1/btc/health' \
-H 'X-API-Key: YOUR_KEY' \
-H 'Accept: application/json'
{
"status": "ok",
"time": "2026-09-02T07:38:18+00:00",
"chain": "main",
"blocks": 965138,
"headers": 965138,
"verificationProgress": 1
}
Authorization: Bearer YOUR_KEY is also accepted and returns the same data — the API key doubles as a personal access token. Prefer X-API-Key anyway: request statistics in the dashboard are only recorded on the X-API-Key path, so a Bearer-based integration shows up as zero usage on your account page.
If you send both, X-API-Key wins outright — a bad X-API-Key is rejected with 401 even when the Authorization header carries a valid key.
Authentication failures
Two distinct messages, both 401, both worth logging separately:
{ "message": "Unauthorized: API Key or Bearer token required" }
No key at all — header missing, or present but empty.
{ "message": "Unauthorized: Invalid or inactive API Key" }
Key was sent but does not match an active key. Covers "typo", "revoked" and "deactivated in the dashboard" alike; the API deliberately does not distinguish them.
Always send Accept: application/json
This is the single biggest source of surprise on this API.
Without Accept: application/json, framework-level failures render Laravel's HTML error page and validation failures come back as an opaque 500. Your JSON parser will throw on a response that has a perfectly good explanation in it.
Same three broken requests, with and without the header:
| Request | Without Accept | With Accept: application/json |
|---|---|---|
| Path that matches no route | 404 + HTML page | 404 + {"message": "The route api/v1/trx/account/balance/nope could not be found."} |
POST to a GET-only route | 405 + HTML page | 405 + {"message": "The POST method is not supported for route api/v1/btc/health. Supported methods: GET, HEAD."} |
POST /api/v1/webhooks with a bad body | 500 + {"message": "Internal server error"} | 422 + full field-by-field errors map |
That 500 is not a server fault. A validation failure without Accept produces a redirect, and /api/v1 converts every 3xx to 500 on purpose — a redirect is useless to a JSON client and would otherwise vanish from your usage statistics. Adding the header turns it back into the 422 you actually wanted:
{
"message": "The coin field is required. (and 2 more errors)",
"errors": {
"coin": ["The coin field is required."],
"webhook_url": ["The webhook url field is required."],
"addresses": ["The addresses field is required."]
}
}
Note also that a path parameter which fails its route constraint — a non-numeric block height, for instance — is a routing miss, not a validation error. It comes back as the 404 above, never as a 422.
Error shapes
There is no single error envelope. Which one you get depends on the endpoint, so check for the key you expect rather than assuming:
| Shape | Where |
|---|---|
{"error": "Could not connect to BTC node."} | Most /btc, /eth, /trx endpoints |
{"message": "…"} | Authentication failures, and framework 404/405 |
{"message": "…", "errors": {…}} | 422 validation failures (webhooks, request bodies) |
{"status": "error", "message": "…"} | The /health endpoints only |
{"error": {"code": -32601, "message": "…"}} | The /jsonrpc proxies |
Two behaviours to code around specifically:
500does not reliably mean "the node is down". The node-backed endpoints collapse most upstream failures intoCould not connect to <COIN> node.— an unknown txid, an unparseable address and a genuine outage all look identical. Check/healthbefore concluding the node is unavailable.200does not always mean success.POST /api/v1/trx/transactions/broadcastanswers200even when java-tron rejects the transaction; branch onresult === truein the body. The/jsonrpcproxies likewise put method-level failures inerrorwhile the transport succeeds.
Rate limits
There are none on /api/v1 today. No RateLimit-* or X-RateLimit-* headers are returned, and no 429 is issued. This is deliberate: adding an external throttle would break existing integrations.
That is not a licence to hammer the API — you are talking to real nodes, and getblock on a busy Bitcoin block expands to several megabytes of JSON. Poll on a sane interval, or better, use webhooks so the platform pushes to you instead.
Per-request usage is recorded per key and visible at settla.net/app/keys — again, only for requests sent with X-API-Key.
Quickstart
Three calls that prove your credentials, connectivity and parsing all work:
export SETTLA_API_KEY='YOUR_KEY'
# 1. Is the node up, and how far along is it?
curl 'https://settla.net/api/v1/btc/health' \
-H "X-API-Key: $SETTLA_API_KEY" -H 'Accept: application/json'
# 2. Read a real transaction.
curl 'https://settla.net/api/v1/btc/transactions/5fc111d07140a808ba08ac28f61fd436efbfe9d84f5437abe980b42c8d9f0a5e' \
-H "X-API-Key: $SETTLA_API_KEY" -H 'Accept: application/json'
# 3. Confirm your error handling: this one must come back 401.
curl -i 'https://settla.net/api/v1/btc/health' \
-H 'X-API-Key: definitely-not-a-key' -H 'Accept: application/json'
Every endpoint page in this reference carries a ready-to-run curl block in the same form — copy it, export SETTLA_API_KEY, and it runs as-is.
Keys and custody
Settla never needs your private keys. The Bitcoin and Ethereum flows are build-and-sign-locally, then broadcast: POST /api/v1/btc/transactions/send-raw and POST /api/v1/eth/transactions/send-raw take a signed hex blob and nothing else.
Four Tron endpoints are the exception — they still accept or return a private key and are deprecated, with a sunset date of 2026-12-01. They are marked ⚠️ in the sidebar. Migrate to POST /api/v1/trx/transactions/create → sign locally → POST /api/v1/trx/transactions/broadcast.