Documentation
API reference
Generated from the OpenAPI served by Links (version 2026-09-18, fetched 2026-11-09).
Status
What this reference is and is not
Forklink does not have an open API yet. This is the API of the link product Forklink is built on; Forklink's public address (planned at api.forklink.co) does not exist yet. The route, field and code names below are those of the OpenAPI deployed in staging and may change before launch.
Authentication
Keys, permissions and rate
- Key: header
Authorization: Bearer cl_live_…(cl_test_…in staging). Keys are created in the workspace's Links panel, not through the API: a key cannot create keys (tested: 403). - Permissions:
full,read(GET only) andtrack(only/track/*, for your site's backend). Tested: areadkey reads (200) and cannot write (403). - Rate: the OpenAPI declares 20 requests per second per key with a burst of 40; beyond that, 429 with
retry-after. Observed in staging: with 300 parallel requests, 140 received 429 (retry-after 1). - New accounts: when the new-account policy is on (it is in staging), keys and custom domains are unavailable until the account is verified (403
ACCOUNT_NOT_VERIFIED). - Base server:
/apion the API host.
Tested examples
Four calls that work today
Run on 2026-11-09 against Links staging (OpenAPI version 2026-09-18) with a cl_test_… key from a test tenant: 17 of 18 checks passed; the keys and the test link were deleted afterwards.
# List
curl -s "$BASE/links?limit=5" -H "Authorization: Bearer $KEY"
# Create
curl -s -X POST "$BASE/links" -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"destinationUrl":"https://example.com/launch","slug":"launch","title":"Launch","utmSource":"newsletter","utmMedium":"email","utmCampaign":"launch"}'
# Analytics for the last 7 days
curl -s "$BASE/links/$ID/analytics?days=7" -H "Authorization: Bearer $KEY"
# Delete
curl -s -X DELETE "$BASE/links/$ID" -H "Authorization: Bearer $KEY"Replace $BASE with the API server (https://<host>/api), $KEY with your key and $ID with the id returned on create. Verified responses: the list returns {items, limit, page, total}; create returns the link (201) with id, slug, domain, destinationUrl, status, totalClicks…; analytics returns totalClicks, uniqueClicks, timeseries, byCountry, byReferrer…; delete answers 204.
Errors
Codes the API returns
Errors look like {"error": "…", "code": "…"}. Verified in staging: 400 INVALID_BODY (with details), 401 MISSING_API_KEY, 403 FORBIDDEN (insufficient permission) and 429 with retry-after.
402 (plan limits): built, not verified. By the meters design, reaching the active-links or custom-domains cap makes the API answer 402 with COMMERCIAL_LIMIT_REACHED (LINKS_ACTIVE_LIMIT_REACHED or CUSTOM_DOMAINS_LIMIT_REACHED, with limit and current); links already published keep redirecting. That code landed but the service deployed in staging is older (the deployed OpenAPI does not list it): I could not test it. Exceeding the month's clicks produces no 402: redirects continue and the analytics detail for the excess stops being stored. Per-plan caps are not approved for production.
Webhooks
Events and signature
Events: link.created, link.updated, link.archived, link.clicked, link.click_limit_reached, link.expired, conversion.lead, conversion.sale, domain.verified, app.opened, app.installed. Svix-style signature (webhook-id, webhook-timestamp, webhook-signature: v1,<base64 HMAC-SHA256> over {id}.{ts}.{body}), up to 8 retries with growing delay; the endpoint is disabled after 50 consecutive failures. Source: Links' OpenAPI and code; I did not test them end to end in this delivery.
Findings
Differences between the OpenAPI and reality in staging
GET /status.jsonis listed as public under/api, but there it asks for a key (401): the public route is/status.jsonat the host root.GET /links/{id}/qranswered 500 INTERNAL_ERROR in staging on 2026-11-09: I leave it out of the tested examples. The free QR tool on this site does not depend on the API.
Reference
All operations (73)
Links
| Method | Path | Description (from the OpenAPI) | Key |
|---|---|---|---|
| GET | /links | Listar enlaces | required |
| POST | /links | Crear un enlace | required |
| POST | /links/bulk | Crear hasta 100 enlaces | required |
| PATCH | /links/bulk | Editar en bloque | required |
| DELETE | /links/bulk | Archivar en bloque | required |
| POST | /links/import | Importar CSV (hasta 1.000 filas) | required |
| GET | /links/slug/suggest | Un slug libre | required |
| GET | /links/{id} | Un enlace | required |
| PATCH | /links/{id} | Editar un enlace | required |
| DELETE | /links/{id} | Archivar (borrado lógico) | required |
| POST | /links/{id}/archive | Archivar | required |
| POST | /links/{id}/duplicate | Duplicar con reglas, píxeles y UTM | required |
| GET | /links/{id}/history | Historial de cambios | required |
Analytics
| Method | Path | Description (from the OpenAPI) | Key |
|---|---|---|---|
| GET | /links/{id}/analytics | Analítica de un enlace | required |
| GET | /links/{id}/analytics/export.csv | Clicks crudos en CSV | required |
| GET | /analytics/summary | Resumen del workspace (con top de enlaces y conversiones) | required |
| GET | /analytics/export.csv | Todos los clicks del workspace en CSV | required |
Conversions
| Method | Path | Description (from the OpenAPI) | Key |
|---|---|---|---|
| GET | /links/{id}/conversions | Leads y ventas de un enlace | required |
| POST | /track/lead | Registrar un lead | required |
| POST | /track/sale | Registrar una venta | required |
Domains
| Method | Path | Description (from the OpenAPI) | Key |
|---|---|---|---|
| GET | /domains | Dominios cortos propios | required |
| POST | /domains | Registrar un dominio | required |
| POST | /domains/{id}/verify | Volver a comprobar | required |
| POST | /domains/{id}/default | Hacerlo el dominio por defecto | required |
| DELETE | /domains/{id} | Quitar | required |
UTM presets
| Method | Path | Description (from the OpenAPI) | Key |
|---|---|---|---|
| GET | /utm-presets | Listar | required |
| POST | /utm-presets | Crear | required |
| PATCH | /utm-presets/{id} | Editar | required |
| DELETE | /utm-presets/{id} | Borrar | required |
Tags
| Method | Path | Description (from the OpenAPI) | Key |
|---|---|---|---|
| GET | /tags | Listar | required |
| POST | /tags | Crear | required |
| PATCH | /tags/{id} | Renombrar | required |
| DELETE | /tags/{id} | Borrar | required |
Groups
| Method | Path | Description (from the OpenAPI) | Key |
|---|---|---|---|
| GET | /groups | Listar | required |
| POST | /groups | Crear | required |
| PATCH | /groups/{id} | Editar | required |
| DELETE | /groups/{id} | Borrar (los enlaces quedan sin grupo) | required |
QR
| Method | Path | Description (from the OpenAPI) | Key |
|---|---|---|---|
| GET | /links/{id}/qr | Imagen QR del enlace | required |
| PATCH | /links/{id}/qr | Estilo del QR | required |
| GET | /links/{id}/qr/config | Estilo guardado | required |
Link-in-bio
| Method | Path | Description (from the OpenAPI) | Key |
|---|---|---|---|
| GET | /bio | Páginas | required |
| POST | /bio | Crear (nace en borrador) | required |
| GET | /bio/{id} | Una página con sus bloques | required |
| PATCH | /bio/{id} | Editar | required |
| DELETE | /bio/{id} | Borrar | required |
| POST | /bio/{id}/publish | Publicar | required |
| POST | /bio/{id}/unpublish | Despublicar | required |
| POST | /bio/{id}/items | Añadir bloque | required |
| POST | /bio/{id}/items/reorder | Reordenar | required |
| PATCH | /bio/{id}/items/{itemId} | Editar bloque | required |
| DELETE | /bio/{id}/items/{itemId} | Quitar bloque | required |
Webhooks
| Method | Path | Description (from the OpenAPI) | Key |
|---|---|---|---|
| GET | /webhooks | Listar | required |
| POST | /webhooks | Crear (devuelve el secreto una vez) | required |
| GET | /webhooks/{id} | Uno | required |
| PATCH | /webhooks/{id} | Editar / activar / desactivar | required |
| DELETE | /webhooks/{id} | Borrar | required |
| POST | /webhooks/{id}/rotate-secret | Rotar el secreto | required |
| POST | /webhooks/{id}/test | Mandar un evento de prueba | required |
| GET | /webhooks/{id}/deliveries | Últimas 50 entregas | required |
| POST | /webhooks/{id}/deliveries/{deliveryId}/retry | Reintentar una entrega | required |
Integrations
| Method | Path | Description (from the OpenAPI) | Key |
|---|---|---|---|
| GET | /integrations | Integraciones de anuncios del workspace | required |
| PUT | /integrations/{provider} | Crear o cambiar (meta) | required |
| DELETE | /integrations/{provider} | Quitar | required |
| POST | /integrations/{provider}/test | Enviar un evento de prueba | required |
Mobile apps
| Method | Path | Description (from the OpenAPI) | Key |
|---|---|---|---|
| GET | /apps | Apps móviles registradas | required |
| POST | /apps | Registrar una app | required |
| GET | /apps/{id} | Una app | required |
| PATCH | /apps/{id} | Editar (la plataforma no cambia) | required |
| DELETE | /apps/{id} | Quitar | required |
Status
| Method | Path | Description (from the OpenAPI) | Key |
|---|---|---|---|
| GET | /status.json | Estado del servicio | public |
Deep links
| Method | Path | Description (from the OpenAPI) | Key |
|---|---|---|---|
| GET | /resolve/{slug} | Resolver un enlace desde la app | public |
| POST | /deferred/claim | Reclamar el deep link diferido tras instalar | public |
| POST | /app-events | Evento de la app (abrió / se instaló) | public |
Back to the documentation
SDKs, package status and what is still to publish.