API reference
Versioned REST API (v1). Full machine-readable spec in OpenAPI 3.1.
Authentication
Create a token in Developers → API tokens and choose scopes. Tokens are shown once and only a hash is stored. API access requires a plan that includes it.
curl https://linkora-demo.devorbit.dev/api/v1/me \
-H "Authorization: Bearer lk_xxxxxxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Create a link
Send an Idempotency-Key header so retries never create duplicates.
curl -X POST https://linkora-demo.devorbit.dev/api/v1/links \
-H "Authorization: Bearer $LINKORA_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 6f1c2f7e-campaign-42" \
-d '{"destination_url":"https://example.com/offer","title":"Offer","tags":["email"],
"utm":{"utm_source":"newsletter","utm_medium":"email","utm_campaign":"spring"}}'
Endpoints
| Method | Path | Scope |
|---|---|---|
| GET | /api/v1/me | — |
| GET | /api/v1/links | links:read |
| POST | /api/v1/links | links:write |
| GET | /api/v1/links/{id} | links:read |
| PATCH | /api/v1/links/{id} | links:write |
| DELETE | /api/v1/links/{id} | links:write |
| POST | /api/v1/links/{id}/pause|resume|archive|unarchive | links:write |
| GET | /api/v1/links/{id}/analytics | analytics:read |
| GET | /api/v1/analytics | analytics:read |
| GET | /api/v1/links/{id}/qr?format=png|svg | qr:read |
Errors
Errors use a consistent JSON envelope with a machine-readable code and the request id (also in the X-Request-Id header).
{ "error": { "code": "plan_limit", "message": "…", "request_id": "c0a8…", "details": { "feature": "links_active", "limit": 25 } } }
Webhook signatures
Each delivery carries Linkora-Signature (t=timestamp,v1=HMAC-SHA256 of "timestamp.body"), Linkora-Event and Linkora-Delivery. Reject old timestamps and de-duplicate delivery ids.
// Node.js verification example
const [t, v1] = header.split(',').map(p => p.split('=')[1]);
const expected = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
const fresh = Math.abs(Date.now() / 1000 - Number(t)) < 300;
const valid = fresh && crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
// Then de-duplicate on the Linkora-Delivery header before processing.
Rate limits
Requests are limited per token (default 120/minute). Exceeding it returns 429 with Retry-After.