DevelopersServer-to-server calls authenticate with an API key: send Authorization: Bearer ek_... on every request. Create keys on the API Keys page — the plaintext key is shown exactly once at creation, so store it securely. Keys are scoped to your developer account; revoked keys are rejected immediately.
# Create a key on the API Keys page (the plaintext ek_ key is shown once). # Then authenticate every request with the Authorization header: curl $API/v1/devices \ -H "authorization: Bearer ek_your_api_key"
This portal itself uses a short-lived JWT obtained via POST /v1/auth/login (email + password). Check your current identity with GET /v1/auth/me.
GET /v1/devices · GET /v1/devices/:id · GET /v1/devices/:id/status (live telemetry, proxied from ecandle-cloud)
POST /v1/quote → POST /v1/orders → GET /v1/orders/:id/events (SSE). The amount is price-locked server-side and cannot be tampered with by the client.
curl -X POST $API/v1/quote \
-H "authorization: Bearer ek_your_api_key" \
-H "content-type: application/json" \
-d '{"deviceId":"eCandle-003","chain":"polygon","token":"USDC","tier":"15min"}'GET /v1/revenue/splits · GET /v1/participants/:id/earnings. Every revenue item is split in real time according to its split rule.
Subscribe to payment.* / revenue.* / split.* / device.* / ticket.* events on the Webhooks page. Deliveries are POSTed as JSON with up to 5 attempts and exponential backoff; use the “Send test” button to queue a signed test.ping delivery to your endpoint. Respond with a 2xx status to acknowledge.
POST <your callback URL>
content-type: application/json
x-ecandle-event: payment.succeeded
x-ecandle-signature: sha256=6a8f...c21e # HMAC-SHA256 of the raw body
{"type":"payment.succeeded","data":{...},"id":"<deliveryId>"}Every delivery carries an x-ecandle-signature header:sha256=<hex>, the HMAC-SHA256 of the raw request body keyed with your webhook’s signing secret (whsec_..., shown on the Webhooks page). Always verify before trusting a payload:
import { createHmac, timingSafeEqual } from "node:crypto";
// rawBody: the exact request body bytes (do not re-serialize parsed JSON)
// signature: the x-ecandle-signature header, e.g. "sha256=6a8f...c21e"
// secret: your webhook's signing secret (whsec_..., see the Webhooks page)
export function verifyWebhook(rawBody: string, signature: string, secret: string): boolean {
const expected = "sha256=" + createHmac("sha256", secret).update(rawBody).digest("hex");
const a = Buffer.from(signature), b = Buffer.from(expected);
return a.length === b.length && timingSafeEqual(a, b);
}401 unauthorized · 404 not found · 409 conflict (quote expired / order unpaid) · 422 invalid parameters · 504 device timeout.