Skip to the page

REST API

API overview

Authentication, errors, pagination, idempotency and rate limits.

The REST API controls what the dashboard shows: apps, domains, links, statistics, webhooks and the setup of item links. Every endpoint of the reference pages in this section is generated from the same OpenAPI file the API is tested against, so it cannot drift from the code.

Base URL: https://api.becklinks.com/v1

Authentication#

Send a secret key as a bearer token, from your server only:

Bash
  • Keys look like sk_live_… and sk_test_…. Each belongs to one project environment: a test key reads and writes test data only.
  • A key has scopes. Every endpoint lists the scope it needs; a missing scope is 403 insufficient_scope. A publishable key (pk_…) is for apps and is rejected by the REST API.
  • Keys are stored as hashes and shown once. Create and revoke them in the dashboard.
ScopeAllows
links:read, links:writeLinks, resource types, URL templates, the metadata API, invalidation
campaigns:writeCampaigns
analytics:readStatistics and exports of statistics
apps:writeThe iOS, Android and web app settings
domains:writeDomains
webhooks:writeWebhook endpoints and deliveries
attribution:readReading attribution
events:writeEvents sent from your server
privacy:writeDeleting an end user's data (never implied by another scope)

Errors#

Errors are application/problem+json (RFC 9457) with a stable code. Branch on code, never on title or detail. A 422 validation_failed lists each invalid field in errors[] with a JSON Pointer. Every response carries X-Request-Id; quote it when you contact support. All codes are in the error reference.

JSON

Idempotency#

Send an Idempotency-Key header (a UUID, 8 to 255 printable ASCII characters) on a POST to make a retry safe. Within 24 hours the original response is returned with Idempotent-Replayed: true. The same key with a different request is 422 idempotency_key_reused; while the first request still runs it is 409 idempotency_key_in_progress. Server errors and rejected input are not stored, so those can be retried with the same key.

Rate limits#

Limits apply per client IP and per secret key (token buckets with a burst). Every response carries RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset (seconds) for the limit closest to running out. Over a limit you get 429 rate_limited with Retry-After in seconds; wait that long, then retry.

Pagination#

List endpoints take limit (1 to 100, default 25) and cursor, and return { "data": [...], "next_cursor": "…" }. next_cursor is null on the last page. Pass it back as cursor.

Conventions#

JSON keys are snake_case, ids are ULIDs (26 characters), timestamps are ISO 8601 in UTC (Z). New response fields can appear at any time, so ignore fields you do not know. Breaking changes only come with a new major version in the path.

The reference#

Pick a group in the navigation: Applications, Domains, Links, Stats, Resources (resource types, URL templates, the metadata API, previews and invalidation) and Webhooks. For the SDK endpoints your app calls with a publishable key, use the Flutter SDK; you do not call them by hand.

Verify it works#

Bash

200 with data means the key and scope work. 401 invalid_api_key means the key is wrong, expired or revoked; 403 insufficient_scope means it lacks links:read.