API and MCP server

Create tokens in your space, under Developers. Each token has limited scopes, can be edited (name and scopes) and revoked at any time.

Authentication

Authorization: Bearer rl_live_…

JSON responses. Errors: { "error": { "code", "message" } }. Rate limit by plan (Solo 20, Pro 60, Agence 120 requests per minute) and at most 1 request per second, shown in the X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Burst headers. Beyond: 429 with Retry-After. Service under heavy load: 503 with Retry-After. To create many links, use /v1/links/batch.

Updating: POST or PATCH

The three update endpoints accept POST as well as PATCH, on the same path and with the same body. Prefer POST: some infrastructure (firewalls, hosting front ends, corporate proxies) drops PATCH requests before they reach the service, and the connection is then reset with no HTTP response. The X-HTTP-Method-Override: PATCH header and the _method field are accepted too; they are not required.

curl -X POST https://api.reli.es/v1/links/42 \
  -H "Authorization: Bearer rl_live_…" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://exemple.fr/nouvelle-page"}'

Create a link

curl https://api.reli.es/v1/links \
  -H "Authorization: Bearer rl_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://exemple.fr/offre",
    "slug": "offre-hiver",
    "tags": ["sms"],
    "utm": {"source": "sms", "campaign": "hiver"},
    "expires_at": "2026-12-31T23:59:00+01:00"
  }'
201 Created
{
  "data": {
    "id": 42,
    "short_url": "https://reli.es/offre-hiver",
    "domain": "reli.es",
    "slug": "offre-hiver",
    "destination": "https://exemple.fr/offre",
    "title": null,
    "status": "active",
    "tags": ["sms"],
    "utm": {"source": "sms", "campaign": "hiver"},
    "protected": false,
    "starts_at": null,
    "ends_at": "2026-12-31T23:59:00+01:00",
    "expired_url": null,
    "clicks": 0,
    "qr_svg": "https://api.reli.es/v1/links/42/qr.svg",
    "created_at": "2026-09-29T10:12:04+02:00"
  }
}

Field names

The response names the destination “destination” and the end date “ends_at”. On input both spellings are accepted: url or destination, expires_at or ends_at. Any other name is refused with a 422 that names it — a misspelled field is never silently ignored.

422 Unprocessable Content
{ "error": {
  "code": "unknown_field",
  "message": "Champ inconnu : lien. Champs acceptés : url, destination, …",
  "unknown": ["lien"],
  "accepted": ["url", "destination", "title", "tags", "utm", "starts_at", "expires_at", "ends_at", "expired_url", "password"]
} }

Listing links

Filters: tag, status (active, archived, blocked, review), domain, q, limit (100 max) and cursor. The next-page cursor sits at the root of the response; it is null on the last page. Links belonging to bio pages and campaigns are not in this list.

GET https://api.reli.es/v1/links?tag=sms&limit=50
{ "data": [ { "id": 42, … } ], "next_cursor": "42" }

Statistics

GET /v1/links/{id}/stats?days=30 (1 to 365 days). A click is recorded straight away and shows up at once. Repeat openings by the same visitor within 30 minutes count in repeats, never in clicks. A call coming from a server (no display language, HEAD, or prefetched by the browser) counts in bots: a command-line test therefore does not raise clicks.

{ "data": {
  "days": 30, "clicks": 128, "uniques": 96, "qr": 12, "bots": 31, "repeats": 7,
  "previous_period_clicks": 88,
  "daily": [ {"date": "2026-09-01", "clicks": 4}, … ],
  "countries": [ {"label": "FR", "n": 101}, … ],
  "cities": [ … ], "devices": [ … ], "sources": [ … ],
  "link": { "id": 42, "short_url": "https://reli.es/offre-hiver" }
} }

Link endings

Chosen link ending (slug): 2 to 64 characters, lowercase letters, digits and hyphens, no hyphen at the start or the end. Uppercase input is lowercased. An ending already taken, reserved or blocked returns a 422 whose message suggests a variant. An ending is never reassigned, even after archiving.

Without a slug, the service assigns a six-character lowercase ending with no ambiguous character (no 0 or o, no 1, l or i): readable under a printed QR code and easy to dictate over the phone.

Endpoints

MethodPathPermissionRole
POST/v1/linkslinks:writeCreate a link: url, domain, slug, title, tags, utm, starts_at, expires_at, expired_url, password
POST/v1/links/batchlinks:writeCreate up to 100 links: { "links": [ … ] }; 207 response with one row per link
GET/v1/linkslinks:readList: tag, status, domain, q, cursor, limit (100 at most)
GET/v1/links/{id}links:readRead a link
POST · PATCH/v1/links/{id}links:writeEdit destination, title, tags, dates, UTM
DELETE/v1/links/{id}links:writeArchive (the link ending is never reassigned)
GET/v1/links/{id}/statsstats:readStatistics: days (1 to 365)
GET/v1/links/{id}/qr.svglinks:readQR code SVG or PNG
GET/v1/domainsdomains:readUsable domains. This scope is only needed here: creating a link on reli.es does not require it.
GET · POST · PATCH/v1/pages/{handle}pages:read · pages:writeRead a bio page, edit title and bio
GET/v1/account—Plan, limits and usage
GET/v1/managed-accountsaccounts:managedManaged accounts, targeted with the Relies-Account header

Campaigns: one link per contact

Reserved for agency accounts and the accounts they manage. A campaign carries a destination, a domain, tracking parameters and an end date; each contact then gets its own link ending, created in batches of 100 in a single request. The contact reference (ref) is your own identifier: 1 to 64 characters, letters, digits, dot, colon, hyphen and underscore. It is stored as is: never put a name, a phone number or an e-mail address in it.

MethodPathRole
GET · POST/v1/campaignsList, create: name, url, domain, utm, expires_at, expired_url, kore_ref
GET · POST · PATCH/v1/campaigns/{id}Read, update: name, url, expires_at, expired_url, kore_ref
POST/v1/campaigns/{id}/contactsAdd 1 to 100 contacts in a single request: { "contacts": [ {"ref": "c-1024"}, {"ref": "c-1025", "url": "https://exemple.fr/page-b"} ] }
GET/v1/campaigns/{id}/contactsList the contacts: clicked, clicked_since, limit (500 max)
DELETE/v1/campaigns/{id}/contacts/{ref}Forget a contact: its reference is erased, the link is archived
curl https://api.reli.es/v1/campaigns/7/contacts \
  -H "Authorization: Bearer rl_live_…" \
  -H "Content-Type: application/json" \
  -d '{"contacts": [{"ref": "c-1024"}, {"ref": "c-1025", "url": "https://exemple.fr/page-b"}]}'
200 OK (207 if a row fails)
{ "data": [ { "index": 0, "ref": "c-1024", "ok": true, "created": true,
              "link": { "id": 512, "short_url": "https://reli.es/k7m4qp", … } }, … ],
  "created": 2, "existing": 0, "failed": 0 }

A reference the campaign already knows returns the existing link (existing): the same batch can be replayed without creating duplicates. Each contact's first click fires the campaign.contact_clicked webhook.

Token scopes

links:read · links:write · stats:read · pages:read · pages:write · domains:read · campaigns:read · campaigns:write · accounts:managed

A missing scope returns a 403 “forbidden” naming the expected scope. A token's scopes can be changed in your space, under Developers, without changing its value: tools already connected keep working.

Webhooks

Events: link.created, link.blocked, link.clicked (grouped by minute), page.form_submitted, campaign.contact_clicked (managed accounts). Each delivery carries the X-Relies-Signature header: t=timestamp,v1=signature, where the signature is the HMAC-SHA256 of “timestamp.body” with your secret. Reject deliveries older than 5 minutes. Three retries on failure: after 1 minute, 10 minutes, 1 hour.

$payload = file_get_contents('php://input');
[$t, $v1] = sscanf($_SERVER['HTTP_X_RELIES_SIGNATURE'], 't=%d,v1=%s');
$valid = abs(time() - $t) < 300
    && hash_equals(hash_hmac('sha256', $t.'.'.$payload, $secret), $v1);

MCP server

Address: https://api.reli.es/mcp · HTTP transport, same token as the API.

claude mcp add --transport http reli-es https://api.reli.es/mcp \
  --header "Authorization: Bearer rl_live_…"
ToolRole
liens_creerCreate one or more links
liens_chercherSearch by destination, tag, status
liens_statsStatistics for a link or the account
lien_modifierEdit destination, title, tags, dates
lien_archiverArchive, with explicit confirmation
page_lire · page_modifierRead a bio page, add a link button
qr_exporterQR code SVG or PNG address
compte_etatPlan, limits and usage