Links for every item
Metadata API
The endpoint that gives each shared link its title, description and image.
When a chat app or social network asks for a link, Beck Links needs the title, description and image of that item. They live in your system, so you provide one read-only endpoint per resource type, and Beck Links calls it, validates the answer, caches it and renders the card as server-side HTML.
The endpoint#
One GET per type, for example https://api.example.com/public/share/challenge/{id}.
httpson port 443, on a public address. Private, loopback and link-local addresses are refused, and redirects are not followed.- Optional authentication: none,
Authorization: Bearer <secret>, or a header of your choice such asX-Api-Key. The secret is stored encrypted, shown once as a hint, and never returned by the API. - Beck Links sends
Accept: application/jsonandUser-Agent: BeckLink/1. - Answer with
Content-Type: application/json, at most 256 KiB, within the time you configure (200 to 3000 ms; two quick retries on network errors, timeouts and5xxwhile the budget lasts). - Use only the item id to find the item. Never expect or accept a referral or a user identifier here: the answer is cached and shared by everyone who opens a link to the item.
{
"id": "4521",
"type": "challenge",
"status": "active",
"title": "Weekend Fitness Challenge",
"description": "Join the challenge and track your progress.",
"image_url": "https://cdn.example.com/challenges/4521.jpg",
"canonical_url": "https://example.com/challenges/4521",
"app_path": "/challenges/4521"
}Map your fields#
The field names are yours. You tell Beck Links where each value is with a simple path:
| Beck Links field | Example path | Rule |
|---|---|---|
title | $.title | Required; shown up to 90 characters |
description | $.description | Up to 200 characters |
image_url | $.images[0].url | https only, on a host in your allowed list; recommended 1200 by 630 pixels |
canonical_url | $.canonical_url | Your public web page of the item |
deep_link_path | $.app_path | The in-app route |
web_fallback_url | $.web_url | Where web visitors go |
resource_status | $.status | See below |
A path is $ followed by dotted names, ['names'] and array positions ($.data.name, $.images[0].url).
No wildcards, filters or scripts. You can set defaults for missing values and choose which fields are
required (the default is the title).
Status. You say which of your values mean published, unpublished and deleted, for example
published: ["active", "live"]. An unpublished or deleted item gets a plain "not available" card
without your data. 404 and 410 answers mean the item does not exist and are remembered for a few
minutes (default 5).
Settings#
| Setting | Default | Range |
|---|---|---|
| Timeout | 1500 ms | 200 to 3000 ms |
Cache time (ttl_seconds) | 900 s | 30 s to 24 h |
Remember "not found" (negative_ttl_seconds) | 300 s | 0 to 1 h |
Serve an old copy when your API fails (stale_if_error_seconds) | 24 h | 0 to 7 days |
| Parallel calls | 4 | 1 to 20 |
| Calls per minute | 120 | 1 to 6000 |
| Allowed image hosts | none | Up to 20 (cdn.example.com or *.example.com) |
Beck Links calls your endpoint at most once per item per cache period, protects it with a circuit breaker when it keeps failing, and never calls it for a person who taps a link.
Escaping and safety#
All text is HTML-escaped by Beck Links. Do not return HTML. An image that is not https, not on an
allowed host, or that points at a private address is dropped (the card then uses your app's icon).
The first request of a crawler is answered with the card in the initial HTML, with no JavaScript
needed; the og:url is the link without its query, so a referral never ends up in the card.
Verify it works#
In Resources, open the type's Metadata API, use Test with a real id (it shows the status, latency and the mapped fields, or the exact reason it failed), then Preview a link. From a terminal, act as a crawler:
curl -A 'facebookexternalhit/1.1' 'https://acme-test.becklinks.com/c/4521?ref=A'Look for og:title, og:description, og:image and an og:url that ends in /c/4521. Change a
ref and the card does not change, and your endpoint logs one call.