Developer Docs

API Reference

Programmatically create short links, manage forms, build pages, and access analytics. Everything you can do in the dashboard, you can do via the API.

Base URLhttps://usebeckon.com/api/v1

Getting Started#

The Beckon API is a RESTful JSON API that lets you manage every aspect of your account programmatically. All requests are made over HTTPS to https://usebeckon.com/api/v1.

Request and response bodies are JSON-encoded. All timestamps are returned as ISO 8601 strings in UTC.

Quick example

Create a short link in a single request:

cURL
curl -X POST https://usebeckon.com/api/v1/links \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/my-very-long-page",
    "code": "demo",
    "tags": ["marketing"]
  }'
Response
{
  "data": {
    "id": "lnk_abc123",
    "code": "demo",
    "short_url": "https://gtg.sh/demo",
    "url": "https://example.com/my-very-long-page",
    "clicks": 0,
    "tags": ["marketing"],
    "created_at": "2026-03-14T12: 00: 00Z"
  }
}

Authentication#

All API requests require a valid API key sent in the Authorization header as a Bearer token.

Header
Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx

API keys are scoped to your team and carry the same permissions as the team member who created them. Keys always start with the gtg_sk_ prefix.

Generate an API key from Dashboard → Settings → API Keys. Keep your key secret and never expose it in client-side code.

Rate Limits#

Rate limits are applied per API key based on your subscription tier.

PlanRequests / minute
Free30
Pro300

Every response includes rate-limit headers:

ParameterTypeRequiredDescription
X-RateLimit-LimitintegerNoMaximum requests allowed per window.
X-RateLimit-RemainingintegerNoRequests remaining in the current window.
X-RateLimit-ResetintegerNoUnix timestamp (seconds) when the window resets.

When you exceed the limit you will receive a 429 Too Many Requests response. Use the X-RateLimit-Reset header to wait before retrying.

Error Handling#

Errors follow a consistent format across all endpoints:

Response
{
  "error": {
    "code": "validation_error",
    "message": "The url field is required.",
    "details": {
      "field": "url"
    }
  }
}
HTTP StatusError CodeDescription
400validation_errorInvalid or missing request parameters.
401unauthenticatedMissing or invalid API key.
403forbiddenAPI key lacks permission for this action.
404not_foundThe requested resource does not exist.
409conflictResource already exists (e.g., duplicate short code).
429rate_limitedToo many requests. Slow down and retry.
500server_errorAn unexpected error occurred on our end.

Pagination#

List endpoints use cursor-based pagination. Pass cursor and limit as query parameters.

ParameterTypeRequiredDescription
cursorstringNoOpaque cursor from a previous response. Omit for the first page.
limitintegerNoNumber of items to return. Default 20, max 100.
Response
{
  "data": [ "..." ],
  "meta": {
    "cursor_next": "eyJpZCI6MTAwfQ",
    "has_more": true
  }
}

When has_more is false, you have reached the last page.

Create, read, update, and delete short links. Each link belongs to a team and can optionally have a custom code, password, expiration, and tags.

ParameterTypeRequiredDescription
cursorstringNoPagination cursor.
limitintegerNoItems per page (default 20, max 100).
searchstringNoFilter by URL or code.
tagstringNoFilter by tag name.
domainstringNoFilter by custom domain.
cURL
curl https://usebeckon.com/api/v1/links?limit=5 \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx"
Response
{
  "data": [
    {
      "id": "lnk_abc123",
      "code": "demo",
      "short_url": "https://gtg.sh/demo",
      "url": "https://example.com",
      "clicks": 142,
      "tags": ["marketing"],
      "password_protected": false,
      "expires_at": null,
      "created_at": "2026-03-10T08: 30: 00Z",
      "updated_at": "2026-03-12T14: 22: 00Z"
    }
  ],
  "meta": {
    "cursor_next": "eyJpZCI6MTAwfQ",
    "has_more": true
  }
}
ParameterTypeRequiredDescription
urlstringYesThe destination URL to shorten.
codestringNoCustom short code (7 chars max). Auto-generated if omitted.
domainstringNoCustom domain (must be verified). Defaults to the default short URL domain.
tagsstring[]NoArray of tag names.
passwordstringNoRequire this password before redirecting.
expires_atstringNoISO 8601 expiration date.
max_clicksintegerNoDisable the link after this many clicks.
utm_sourcestringNoUTM source parameter to append.
utm_mediumstringNoUTM medium parameter to append.
utm_campaignstringNoUTM campaign parameter to append.
cURL
curl -X POST https://usebeckon.com/api/v1/links \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/launch",
    "code": "launch",
    "tags": ["product", "launch"],
    "expires_at": "2026-12-31T23:59:59Z"
  }'
Response
{
  "data": {
    "id": "lnk_xyz789",
    "code": "launch",
    "short_url": "https://gtg.sh/launch",
    "url": "https://example.com/launch",
    "clicks": 0,
    "tags": ["product", "launch"],
    "password_protected": false,
    "expires_at": "2026-12-31T23: 59: 59Z",
    "max_clicks": null,
    "created_at": "2026-03-14T12: 00: 00Z",
    "updated_at": "2026-03-14T12: 00: 00Z"
  }
}
ParameterTypeRequiredDescription
idstringYesLink ID (lnk_...) or short code.
cURL
curl https://usebeckon.com/api/v1/links/lnk_abc123 \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx"
ParameterTypeRequiredDescription
idstringYesLink ID.
urlstringNoNew destination URL.
codestringNoNew short code.
tagsstring[]NoReplace tags.
passwordstring | nullNoSet or remove password (null to remove).
expires_atstring | nullNoSet or remove expiration.
max_clicksinteger | nullNoSet or remove click limit.
cURL
curl -X PATCH https://usebeckon.com/api/v1/links/lnk_abc123 \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://example.com/updated" }'
ParameterTypeRequiredDescription
idstringYesLink ID.
cURL
curl -X DELETE https://usebeckon.com/api/v1/links/lnk_abc123 \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx"
Response
{ "data": { "deleted": true } }

Archives a link by setting is_active to false. Archived links stop redirecting but are not deleted and can be restored.

ParameterTypeRequiredDescription
idstringYesLink ID.
cURL
curl -X POST https://usebeckon.com/api/v1/links/lnk_abc123/archive \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx"
Response
{
  "data": {
    "id": "lnk_abc123",
    "code": "demo",
    "is_active": false,
    "archived_at": "2026-03-14T12: 00: 00Z"
  }
}

Create up to 100 links in a single request. Each item in the array follows the same schema as POST /v1/links.

ParameterTypeRequiredDescription
linksobject[]YesArray of link objects (max 100).
cURL
curl -X POST https://usebeckon.com/api/v1/links/bulk \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "links": [
      { "url": "https://example.com/a" },
      { "url": "https://example.com/b", "code": "custom-b" },
      { "url": "https://example.com/c", "tags": ["batch"] }
    ]
  }'
Response
{
  "data": [
    { "id": "lnk_001", "code": "a7xKm2q", "short_url": "https://gtg.sh/a7xKm2q", "url": "https://example.com/a" },
    { "id": "lnk_002", "code": "custom-b", "short_url": "https://gtg.sh/custom-b", "url": "https://example.com/b" },
    { "id": "lnk_003", "code": "p3rTn8v", "short_url": "https://gtg.sh/p3rTn8v", "url": "https://example.com/c" }
  ],
  "meta": {
    "created": 3,
    "errors": 0
  }
}
ParameterTypeRequiredDescription
idstringYesLink ID.
periodstringNo1h, 24h, 7d, 30d, 90d, all (default 30d).
group_bystringNohour, day, country, device, browser, referrer.
cURL
curl "https://usebeckon.com/api/v1/links/lnk_abc123/analytics?period=7d&group_by=day" \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx"
Response
{
  "data": {
    "total_clicks": 847,
    "unique_clicks": 623,
    "timeseries": [
      { "date": "2026-03-08", "clicks": 102, "unique": 78 },
      { "date": "2026-03-09", "clicks": 134, "unique": 99 },
      { "date": "2026-03-10", "clicks": 118, "unique": 85 },
      { "date": "2026-03-11", "clicks": 97, "unique": 72 },
      { "date": "2026-03-12", "clicks": 145, "unique": 110 },
      { "date": "2026-03-13", "clicks": 128, "unique": 92 },
      { "date": "2026-03-14", "clicks": 123, "unique": 87 }
    ],
    "top_countries": [
      { "country": "US", "clicks": 312 },
      { "country": "GB", "clicks": 187 },
      { "country": "DE", "clicks": 98 }
    ],
    "top_referrers": [
      { "referrer": "twitter.com", "clicks": 234 },
      { "referrer": "linkedin.com", "clicks": 156 }
    ]
  }
}

Forms#

Create and manage forms. Each form belongs to a team and contains an array of fields with configurable types, validation, and logic.

GET/v1/formsTry it
ParameterTypeRequiredDescription
cursorstringNoPagination cursor.
limitintegerNoItems per page (default 20, max 100).
statusstringNoFilter by status: draft, published, archived.
cURL
curl https://usebeckon.com/api/v1/forms?status=published \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx"
Response
{
  "data": [
    {
      "id": "frm_abc123",
      "name": "Contact Form",
      "status": "published",
      "submissions_count": 42,
      "fields_count": 5,
      "created_at": "2026-02-01T10: 00: 00Z",
      "updated_at": "2026-03-10T15: 30: 00Z"
    }
  ],
  "meta": {
    "cursor_next": null,
    "has_more": false
  }
}
POST/v1/formsTry it
ParameterTypeRequiredDescription
namestringYesForm name.
descriptionstringNoDescription displayed at the top of the form.
fieldsobject[]YesArray of field definitions (see field types below).
settingsobjectNoForm settings: thank-you message, redirect URL, notifications.
statusstringNodraft or published (default draft).
cURL
curl -X POST https://usebeckon.com/api/v1/forms \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Feedback Form",
    "status": "published",
    "fields": [
      { "type": "short_text", "label": "Name", "required": true },
      { "type": "email", "label": "Email", "required": true },
      { "type": "long_text", "label": "Message", "required": false },
      { "type": "rating", "label": "How would you rate us?", "max": 5 }
    ],
    "settings": {
      "thank_you_message": "Thanks for your feedback!",
      "notification_email": "team@example.com"
    }
  }'
Response
{
  "data": {
    "id": "frm_xyz789",
    "name": "Feedback Form",
    "status": "published",
    "url": "https://gtg.sh/f/frm_xyz789",
    "fields_count": 4,
    "submissions_count": 0,
    "created_at": "2026-03-14T12: 00: 00Z"
  }
}
GET/v1/forms/{id}Try it
ParameterTypeRequiredDescription
idstringYesForm ID (frm_...).
cURL
curl https://usebeckon.com/api/v1/forms/frm_abc123 \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx"
PATCH/v1/forms/{id}Try it
ParameterTypeRequiredDescription
idstringYesForm ID.
namestringNoNew form name.
fieldsobject[]NoReplace all fields.
settingsobjectNoMerge with existing settings.
statusstringNodraft, published, or archived.
cURL
curl -X PATCH https://usebeckon.com/api/v1/forms/frm_abc123 \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{ "status": "archived" }'
DELETE/v1/forms/{id}Try it
ParameterTypeRequiredDescription
idstringYesForm ID.
cURL
curl -X DELETE https://usebeckon.com/api/v1/forms/frm_abc123 \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx"
Response
{ "data": { "deleted": true } }

Form Submissions#

Retrieve and manage submissions for a specific form.

GET/v1/forms/{id}/submissionsTry it
ParameterTypeRequiredDescription
idstringYesForm ID.
cursorstringNoPagination cursor.
limitintegerNoItems per page (default 20, max 100).
statusstringNoFilter: new, read, starred, spam, archived.
sincestringNoISO 8601 date. Only submissions after this date.
untilstringNoISO 8601 date. Only submissions before this date.
cURL
curl "https://usebeckon.com/api/v1/forms/frm_abc123/submissions?status=new&limit=10" \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx"
Response
{
  "data": [
    {
      "id": "sub_001",
      "form_id": "frm_abc123",
      "status": "new",
      "data": {
        "name": "Jane Doe",
        "email": "jane@example.com",
        "message": "Love the product!"
      },
      "metadata": {
        "ip_country": "US",
        "browser": "Chrome",
        "referrer": "https://google.com"
      },
      "created_at": "2026-03-14T09: 15: 00Z"
    }
  ],
  "meta": {
    "cursor_next": null,
    "has_more": false
  }
}
GET/v1/forms/{id}/submissions/{sub_id}Try it
ParameterTypeRequiredDescription
idstringYesForm ID.
sub_idstringYesSubmission ID (sub_...).
cURL
curl https://usebeckon.com/api/v1/forms/frm_abc123/submissions/sub_001 \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx"
PATCH/v1/forms/{id}/submissions/{sub_id}Try it
ParameterTypeRequiredDescription
idstringYesForm ID.
sub_idstringYesSubmission ID.
statusstringYesnew, read, starred, spam, or archived.
cURL
curl -X PATCH https://usebeckon.com/api/v1/forms/frm_abc123/submissions/sub_001 \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{ "status": "read" }'
DELETE/v1/forms/{id}/submissions/{sub_id}Try it
ParameterTypeRequiredDescription
idstringYesForm ID.
sub_idstringYesSubmission ID.
cURL
curl -X DELETE https://usebeckon.com/api/v1/forms/frm_abc123/submissions/sub_001 \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx"
Response
{ "data": { "deleted": true } }

Pages#

Create, read, update, and delete landing pages. Each page belongs to a team and has a slug, template, theme configuration, and an ordered list of content blocks.

GET/v1/pagesTry it
ParameterTypeRequiredDescription
cursorstringNoPagination cursor.
limitintegerNoItems per page (default 20, max 100).
statusstringNoFilter: draft or published.
cURL
curl https://usebeckon.com/api/v1/pages \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx"
Response
{
  "data": [
    {
      "id": "pg_abc123",
      "title": "My Link-in-Bio",
      "slug": "my-links",
      "url": "https://gtg.sh/p/my-links",
      "status": "published",
      "template": "link-in-bio",
      "views": 1234,
      "created_at": "2026-02-15T08: 00: 00Z",
      "updated_at": "2026-03-10T12: 00: 00Z"
    }
  ],
  "meta": {
    "cursor_next": null,
    "has_more": false
  }
}
GET/v1/pages/{id}Try it
ParameterTypeRequiredDescription
idstringYesPage ID (pg_...) or slug.
cURL
curl https://usebeckon.com/api/v1/pages/pg_abc123 \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx"
Response
{
  "data": {
    "id": "pg_abc123",
    "title": "My Link-in-Bio",
    "slug": "my-links",
    "url": "https://gtg.sh/p/my-links",
    "status": "published",
    "template": "link-in-bio",
    "theme": {
      "preset": "midnight",
      "font": "Inter",
      "primary_color": "#3b82f6"
    },
    "blocks": [
      { "type": "hero", "heading": "Hey, I'm Alex", "subheading": "Creator & developer" },
      { "type": "links", "items": [
        { "label": "My Blog", "url": "https://example.com/blog" },
        { "label": "YouTube", "url": "https://youtube.com/@example" }
      ]},
      { "type": "social", "links": { "twitter": "example", "github": "example" } }
    ],
    "seo": {
      "meta_title": "Alex — Links",
      "meta_description": "All my links in one place.",
      "og_image": "https://gtg.sh/og/my-links.png"
    },
    "views": 1234,
    "created_at": "2026-02-15T08: 00: 00Z",
    "updated_at": "2026-03-10T12: 00: 00Z"
  }
}
POST/v1/pagesTry it
ParameterTypeRequiredDescription
titlestringYesPage title.
slugstringYesURL slug (unique within your team).
descriptionstringNoShort description of the page.
template_idstringNoTemplate to base the page on (e.g., link-in-bio, portfolio).
theme_configobjectNoTheme configuration: preset, font, primary_color, etc.
cURL
curl -X POST https://usebeckon.com/api/v1/pages \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "My Portfolio",
    "slug": "portfolio",
    "description": "My personal portfolio page",
    "template_id": "portfolio",
    "theme_config": {
      "preset": "midnight",
      "font": "Inter",
      "primary_color": "#3b82f6"
    }
  }'
Response
{
  "data": {
    "id": "pg_new123",
    "title": "My Portfolio",
    "slug": "portfolio",
    "url": "https://gtg.sh/p/portfolio",
    "status": "draft",
    "template": "portfolio",
    "views": 0,
    "created_at": "2026-03-14T12: 00: 00Z",
    "updated_at": "2026-03-14T12: 00: 00Z"
  }
}
PATCH/v1/pages/{id}Try it
ParameterTypeRequiredDescription
idstringYesPage ID.
titlestringNoNew page title.
slugstringNoNew URL slug.
descriptionstringNoPage description.
statusstringNodraft or published.
seo_titlestringNoSEO meta title override.
seo_descriptionstringNoSEO meta description override.
og_image_urlstringNoOpen Graph image URL.
robots_indexbooleanNoWhether search engines should index this page.
theme_configobjectNoTheme configuration to merge with existing.
cURL
curl -X PATCH https://usebeckon.com/api/v1/pages/pg_abc123 \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Updated Portfolio",
    "seo_title": "Alex — Portfolio",
    "seo_description": "Check out my latest work.",
    "robots_index": true
  }'
Response
{
  "data": {
    "id": "pg_abc123",
    "title": "Updated Portfolio",
    "slug": "my-links",
    "status": "published",
    "seo": {
      "meta_title": "Alex — Portfolio",
      "meta_description": "Check out my latest work.",
      "og_image": null,
      "robots_index": true
    },
    "updated_at": "2026-03-14T14: 00: 00Z"
  }
}
DELETE/v1/pages/{id}Try it
ParameterTypeRequiredDescription
idstringYesPage ID.
cURL
curl -X DELETE https://usebeckon.com/api/v1/pages/pg_abc123 \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx"
Response
{ "data": { "deleted": true } }
POST/v1/pages/{id}/publishTry it

Publishes a draft page, making it publicly accessible at its URL.

ParameterTypeRequiredDescription
idstringYesPage ID.
cURL
curl -X POST https://usebeckon.com/api/v1/pages/pg_abc123/publish \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx"
Response
{
  "data": {
    "id": "pg_abc123",
    "status": "published",
    "published_at": "2026-03-14T12: 00: 00Z"
  }
}
POST/v1/pages/{id}/unpublishTry it

Unpublishes a live page, reverting it to draft status. The public URL will return a 404.

ParameterTypeRequiredDescription
idstringYesPage ID.
cURL
curl -X POST https://usebeckon.com/api/v1/pages/pg_abc123/unpublish \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx"
Response
{
  "data": {
    "id": "pg_abc123",
    "status": "draft",
    "unpublished_at": "2026-03-14T12: 00: 00Z"
  }
}

Page Blocks#

Manage the content blocks within a page. Blocks are ordered and can be of various types (hero, links, text, image, social, form, etc.).

GET/v1/pages/{id}/blocksTry it
ParameterTypeRequiredDescription
idstringYesPage ID.
cURL
curl https://usebeckon.com/api/v1/pages/pg_abc123/blocks \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx"
Response
{
  "data": [
    {
      "id": "blk_001",
      "type": "hero",
      "visible": true,
      "position": 0,
      "config": {
        "heading": "Hey, I'm Alex",
        "subheading": "Creator & developer"
      }
    },
    {
      "id": "blk_002",
      "type": "links",
      "visible": true,
      "position": 1,
      "config": {
        "items": [
          { "label": "My Blog", "url": "https://example.com/blog" },
          { "label": "YouTube", "url": "https://youtube.com/@example" }
        ]
      }
    }
  ]
}
POST/v1/pages/{id}/blocksTry it
ParameterTypeRequiredDescription
idstringYesPage ID.
typestringYesBlock type: hero, links, text, image, social, form, etc.
configobjectYesBlock configuration (varies by type).
visiblebooleanNoWhether the block is visible (default true).
cURL
curl -X POST https://usebeckon.com/api/v1/pages/pg_abc123/blocks \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "text",
    "config": {
      "content": "Welcome to my page! Here you will find all my links."
    },
    "visible": true
  }'
Response
{
  "data": {
    "id": "blk_003",
    "type": "text",
    "visible": true,
    "position": 2,
    "config": {
      "content": "Welcome to my page! Here you will find all my links."
    }
  }
}
PATCH/v1/pages/{id}/blocks/{blockId}Try it
ParameterTypeRequiredDescription
idstringYesPage ID.
blockIdstringYesBlock ID (blk_...).
configobjectNoUpdated block configuration.
visiblebooleanNoShow or hide the block.
typestringNoChange the block type.
cURL
curl -X PATCH https://usebeckon.com/api/v1/pages/pg_abc123/blocks/blk_001 \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "config": {
      "heading": "Hey, I am Alex!",
      "subheading": "Developer & creator"
    }
  }'
DELETE/v1/pages/{id}/blocks/{blockId}Try it
ParameterTypeRequiredDescription
idstringYesPage ID.
blockIdstringYesBlock ID.
cURL
curl -X DELETE https://usebeckon.com/api/v1/pages/pg_abc123/blocks/blk_001 \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx"
Response
{ "data": { "deleted": true } }
POST/v1/pages/{id}/blocks/reorderTry it

Set the display order of all blocks by passing an ordered array of block IDs.

ParameterTypeRequiredDescription
idstringYesPage ID.
block_idsstring[]YesOrdered array of block IDs.
cURL
curl -X POST https://usebeckon.com/api/v1/pages/pg_abc123/blocks/reorder \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "block_ids": ["blk_002", "blk_003", "blk_001"]
  }'
Response
{
  "data": {
    "reordered": true,
    "block_ids": ["blk_002", "blk_003", "blk_001"]
  }
}

Analytics#

Access platform-wide and resource-specific analytics for links, forms, and pages. For per-link analytics, also see GET /v1/links/{id}/analytics above.

GET/v1/analytics/summaryTry it

Returns aggregate statistics across all your links for the given time period.

ParameterTypeRequiredDescription
periodstringNo1h, 24h, 7d, 30d, 90d, all (default 30d).
cURL
curl "https://usebeckon.com/api/v1/analytics/summary?period=30d" \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx"
Response
{
  "data": {
    "total_links": 156,
    "total_clicks": 24893,
    "unique_clicks": 18342,
    "total_forms": 8,
    "total_submissions": 1247,
    "total_pages": 3,
    "total_page_views": 5621,
    "top_links": [
      { "id": "lnk_abc123", "code": "demo", "clicks": 847 },
      { "id": "lnk_def456", "code": "launch", "clicks": 623 },
      { "id": "lnk_ghi789", "code": "blog", "clicks": 412 }
    ],
    "clicks_by_day": [
      { "date": "2026-02-13", "clicks": 782 },
      { "date": "2026-02-14", "clicks": 834 }
    ]
  }
}

Returns aggregate analytics across all links, including timeseries data and breakdowns.

ParameterTypeRequiredDescription
periodstringNo1h, 24h, 7d, 30d, 90d, all (default 30d).
group_bystringNohour, day, country, device, browser, referrer.
cURL
curl "https://usebeckon.com/api/v1/analytics/links?period=7d&group_by=day" \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx"
Response
{
  "data": {
    "total_clicks": 12483,
    "unique_clicks": 8921,
    "timeseries": [
      { "date": "2026-03-08", "clicks": 1702, "unique": 1280 },
      { "date": "2026-03-09", "clicks": 1834, "unique": 1399 },
      { "date": "2026-03-10", "clicks": 1618, "unique": 1185 }
    ]
  }
}
GET/v1/analytics/formsTry it

Returns aggregate analytics across all forms, including submission counts and conversion rates.

ParameterTypeRequiredDescription
periodstringNo1h, 24h, 7d, 30d, 90d, all (default 30d).
cURL
curl "https://usebeckon.com/api/v1/analytics/forms?period=30d" \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx"
Response
{
  "data": {
    "total_submissions": 1247,
    "total_views": 8432,
    "conversion_rate": 14.8,
    "submissions_by_day": [
      { "date": "2026-03-12", "submissions": 42 },
      { "date": "2026-03-13", "submissions": 38 },
      { "date": "2026-03-14", "submissions": 51 }
    ]
  }
}
GET/v1/analytics/pagesTry it

Returns aggregate analytics across all landing pages, including view counts and engagement metrics.

ParameterTypeRequiredDescription
periodstringNo1h, 24h, 7d, 30d, 90d, all (default 30d).
cURL
curl "https://usebeckon.com/api/v1/analytics/pages?period=30d" \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx"
Response
{
  "data": {
    "total_views": 5621,
    "unique_visitors": 4102,
    "views_by_day": [
      { "date": "2026-03-12", "views": 187 },
      { "date": "2026-03-13", "views": 203 },
      { "date": "2026-03-14", "views": 195 }
    ]
  }
}
GET/v1/forms/{id}/analyticsTry it
ParameterTypeRequiredDescription
idstringYesForm ID (frm_...).
periodstringNo1h, 24h, 7d, 30d, 90d, all (default 30d).
cURL
curl "https://usebeckon.com/api/v1/forms/frm_abc123/analytics?period=7d" \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx"
Response
{
  "data": {
    "total_submissions": 142,
    "total_views": 1083,
    "conversion_rate": 13.1,
    "submissions_by_day": [
      { "date": "2026-03-08", "submissions": 18 },
      { "date": "2026-03-09", "submissions": 22 },
      { "date": "2026-03-10", "submissions": 19 }
    ],
    "top_countries": [
      { "country": "US", "submissions": 64 },
      { "country": "GB", "submissions": 31 }
    ]
  }
}
GET/v1/pages/{id}/analyticsTry it
ParameterTypeRequiredDescription
idstringYesPage ID (pg_...).
periodstringNo1h, 24h, 7d, 30d, 90d, all (default 30d).
cURL
curl "https://usebeckon.com/api/v1/pages/pg_abc123/analytics?period=7d" \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx"
Response
{
  "data": {
    "total_views": 1234,
    "unique_visitors": 892,
    "avg_time_on_page": 45,
    "views_by_day": [
      { "date": "2026-03-08", "views": 167 },
      { "date": "2026-03-09", "views": 189 },
      { "date": "2026-03-10", "views": 174 }
    ],
    "top_referrers": [
      { "referrer": "instagram.com", "views": 342 },
      { "referrer": "twitter.com", "views": 218 }
    ]
  }
}

Webhooks#

Receive real-time HTTP callbacks when events happen in your account. Configure webhook endpoints, choose which events to subscribe to, and verify signatures for security.

Event types

EventDescription
link.createdA new short link was created.
link.updatedA link was updated.
link.deletedA link was deleted.
link.clickedA short link was clicked.
form.createdA new form was created.
form.updatedA form was updated.
form.deletedA form was deleted.
form.submission.createdA new form submission was received.
page.createdA new page was created.
page.publishedA page was published.
page.unpublishedA page was unpublished.
page.updatedA page was updated.
page.deletedA page was deleted.

Signature verification

Every webhook delivery includes a Gtg-Signature header containing a timestamp and HMAC-SHA256 signature. Always verify signatures to ensure the payload was sent by Beckon.

Header format
Gtg-Signature: t=1710421200,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd
Node.js verification
import crypto from 'crypto';

function verifyWebhookSignature(payload, header, secret) {
  const [tPart, v1Part] = header.split(',');
  const timestamp = tPart.split('=')[1];
  const signature = v1Part.split('=')[1];

  const signedPayload = timestamp + '.' + payload;
  const expected = crypto
    .createHmac('sha256', secret)
    .update(signedPayload)
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

Retry schedule

If your endpoint returns a non-2xx status code, Beckon will retry delivery with exponential backoff:

AttemptDelay
1Immediate
21 minute
35 minutes
430 minutes
52 hours
68 hours
724 hours

Auto-disable: Webhook endpoints are automatically disabled after 20 consecutive failures. You can re-enable them from the dashboard or via the API.

GET/v1/webhooksTry it
ParameterTypeRequiredDescription
cursorstringNoPagination cursor.
limitintegerNoItems per page (default 20, max 100).
cURL
curl https://usebeckon.com/api/v1/webhooks \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx"
Response
{
  "data": [
    {
      "id": "wh_abc123",
      "url": "https://example.com/webhooks/gtg",
      "events": ["link.created", "link.clicked"],
      "description": "Production webhook",
      "enabled": true,
      "consecutive_failures": 0,
      "created_at": "2026-03-01T10: 00: 00Z",
      "updated_at": "2026-03-10T15: 30: 00Z"
    }
  ],
  "meta": {
    "cursor_next": null,
    "has_more": false
  }
}
POST/v1/webhooksTry it
ParameterTypeRequiredDescription
urlstringYesThe HTTPS URL to receive webhook events.
eventsstring[]YesArray of event types to subscribe to.
descriptionstringNoA friendly label for this endpoint.
cURL
curl -X POST https://usebeckon.com/api/v1/webhooks \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/webhooks/gtg",
    "events": ["link.created", "link.clicked", "form.submission.created"],
    "description": "Production webhook"
  }'
Response
{
  "data": {
    "id": "wh_new456",
    "url": "https://example.com/webhooks/gtg",
    "events": ["link.created", "link.clicked", "form.submission.created"],
    "description": "Production webhook",
    "secret": "whsec_xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "enabled": true,
    "created_at": "2026-03-14T12: 00: 00Z"
  }
}

Important: The secret is only returned once at creation time. Store it securely for signature verification.

GET/v1/webhooks/{id}Try it
ParameterTypeRequiredDescription
idstringYesWebhook ID (wh_...).
cURL
curl https://usebeckon.com/api/v1/webhooks/wh_abc123 \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx"
PATCH/v1/webhooks/{id}Try it
ParameterTypeRequiredDescription
idstringYesWebhook ID.
urlstringNoNew endpoint URL.
eventsstring[]NoReplace subscribed events.
descriptionstringNoUpdated description.
enabledbooleanNoEnable or disable the webhook.
cURL
curl -X PATCH https://usebeckon.com/api/v1/webhooks/wh_abc123 \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "events": ["link.created", "link.clicked", "link.deleted"],
    "enabled": true
  }'
DELETE/v1/webhooks/{id}Try it
ParameterTypeRequiredDescription
idstringYesWebhook ID.
cURL
curl -X DELETE https://usebeckon.com/api/v1/webhooks/wh_abc123 \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx"
Response
{ "data": { "deleted": true } }
POST/v1/webhooks/{id}/testTry it

Sends a test event to the webhook endpoint so you can verify your integration is working correctly.

ParameterTypeRequiredDescription
idstringYesWebhook ID.
cURL
curl -X POST https://usebeckon.com/api/v1/webhooks/wh_abc123/test \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx"
Response
{
  "data": {
    "delivered": true,
    "status_code": 200,
    "response_time_ms": 142,
    "event_type": "webhook.test"
  }
}
GET/v1/webhooks/{id}/deliveriesTry it
ParameterTypeRequiredDescription
idstringYesWebhook ID.
cursorstringNoPagination cursor.
limitintegerNoItems per page (default 20, max 100).
cURL
curl "https://usebeckon.com/api/v1/webhooks/wh_abc123/deliveries?limit=5" \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx"
Response
{
  "data": [
    {
      "id": "dlv_001",
      "event_type": "link.clicked",
      "status_code": 200,
      "success": true,
      "response_time_ms": 87,
      "attempt": 1,
      "delivered_at": "2026-03-14T11: 30: 00Z"
    },
    {
      "id": "dlv_002",
      "event_type": "form.submission.created",
      "status_code": 500,
      "success": false,
      "response_time_ms": 3021,
      "attempt": 1,
      "next_retry_at": "2026-03-14T11: 31: 00Z",
      "delivered_at": "2026-03-14T11: 30: 00Z"
    }
  ],
  "meta": {
    "cursor_next": "eyJpZCI6MTAwfQ",
    "has_more": true
  }
}

Account#

Retrieve account information, check usage against plan limits, and manage API keys programmatically.

GET/v1/accountTry it

Returns the team and subscription details associated with the current API key.

cURL
curl https://usebeckon.com/api/v1/account \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx"
Response
{
  "data": {
    "team_id": "team_abc123",
    "team_name": "My Team",
    "plan": "pro",
    "member_count": 3,
    "created_at": "2025-08-15T10: 00: 00Z"
  }
}
GET/v1/account/usageTry it

Returns current resource usage compared to your plan limits.

cURL
curl https://usebeckon.com/api/v1/account/usage \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx"
Response
{
  "data": {
    "plan": "pro",
    "billing_period": {
      "start": "2026-03-01T00: 00: 00Z",
      "end": "2026-03-31T23: 59: 59Z"
    },
    "links": { "used": 156, "limit": 1000 },
    "clicks": { "used": 24893, "limit": 100000 },
    "forms": { "used": 8, "limit": 25 },
    "pages": { "used": 3, "limit": 10 },
    "team_members": { "used": 3, "limit": 10 },
    "custom_domains": { "used": 1, "limit": 5 },
    "api_keys": { "used": 2, "limit": 5 }
  }
}
GET/v1/account/api-keysTry it

Lists all API keys for your team. Key values are masked for security and only show the last 4 characters.

cURL
curl https://usebeckon.com/api/v1/account/api-keys \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx"
Response
{
  "data": [
    {
      "id": "key_abc123",
      "name": "Production",
      "masked_key": "gtg_sk_...a1b2",
      "last_used_at": "2026-03-14T11: 45: 00Z",
      "created_at": "2026-01-15T08: 00: 00Z"
    },
    {
      "id": "key_def456",
      "name": "Development",
      "masked_key": "gtg_sk_...c3d4",
      "last_used_at": "2026-03-10T09: 00: 00Z",
      "created_at": "2026-02-01T12: 00: 00Z"
    }
  ]
}
POST/v1/account/api-keysTry it
ParameterTypeRequiredDescription
namestringYesA label for the API key (e.g., "Production", "CI/CD").
cURL
curl -X POST https://usebeckon.com/api/v1/account/api-keys \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{ "name": "CI/CD Pipeline" }'
Response
{
  "data": {
    "id": "key_new789",
    "name": "CI/CD Pipeline",
    "key": "gtg_sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "created_at": "2026-03-14T12: 00: 00Z"
  }
}

Important: The full API key is only returned once at creation time. Store it securely — you will not be able to retrieve it again.

DELETE/v1/account/api-keys/{id}Try it

Permanently revokes an API key. Any requests using this key will immediately begin returning 401 Unauthenticated.

ParameterTypeRequiredDescription
idstringYesAPI key ID (key_...).
cURL
curl -X DELETE https://usebeckon.com/api/v1/account/api-keys/key_abc123 \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx"
Response
{ "data": { "deleted": true } }

OAuth 2.0#

Beckon supports OAuth 2.0 for third-party integrations. Users can authorize your application to access their Beckon account without sharing their API key.

Authorization Flow

Beckon uses the Authorization Code + PKCE flow for maximum security.

  1. Redirect the user to the authorization endpoint:
    Authorization URL
    https://usebeckon.com/oauth/authorize?client_id=app_...&redirect_uri=https://yourapp.com/callback&response_type=code&scope=links:read links:write&state=random_state_value&code_challenge=...&code_challenge_method=S256
  2. The user reviews the requested scopes and approves your application.
  3. Beckon redirects to your redirect_uri with ?code=...&state=....
  4. Exchange the authorization code for tokens at POST /api/oauth/token.

Token Endpoint

Exchange an authorization code for an access token and refresh token.

POST/api/oauth/tokenTry it
cURL
curl -X POST https://usebeckon.com/api/oauth/token \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "authorization_code",
    "code": "...",
    "redirect_uri": "https://yourapp.com/callback",
    "client_id": "app_...",
    "client_secret": "secret_...",
    "code_verifier": "..."
  }'
Response
{
  "access_token": "gtg_at_...",
  "refresh_token": "gtg_rt_...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "links:read links:write"
}

Refresh Tokens

Access tokens expire after 1 hour. Use the refresh token to obtain a new access token without requiring the user to re-authorize.

cURL
curl -X POST https://usebeckon.com/api/oauth/token \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "refresh_token",
    "refresh_token": "gtg_rt_...",
    "client_id": "app_...",
    "client_secret": "secret_..."
  }'

Client Credentials

For server-to-server integrations where no user interaction is needed, use the client credentials flow. This grants access scoped to your own account.

cURL
curl -X POST https://usebeckon.com/api/oauth/token \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "client_credentials",
    "client_id": "app_...",
    "client_secret": "secret_..."
  }'

Available Scopes

Request only the scopes your application needs. Scopes are space-delimited in the authorization URL.

ScopeDescription
links:readRead links and their metadata
links:writeCreate, update, and delete links
links:analyticsView click analytics for links
forms:readRead form configurations
forms:writeCreate, update, and delete forms
forms.submissions:readRead form submissions
forms.submissions:writeUpdate and delete form submissions
pages:readRead page configurations and blocks
pages:writeCreate, update, and delete pages
pages:analyticsView page view analytics
analytics:readRead aggregate analytics data
webhooks:readRead webhook configurations
webhooks:writeCreate, update, and delete webhooks
account:readRead account and team information

OAuth App Management API

Register and manage your OAuth applications programmatically.

GET/v1/account/oauth-appsTry it
cURL
curl https://usebeckon.com/api/v1/account/oauth-apps \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx"
POST/v1/account/oauth-appsTry it
cURL
curl -X POST https://usebeckon.com/api/v1/account/oauth-apps \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "My Integration",
    "redirect_uris": ["https://yourapp.com/callback"],
    "scopes": ["links:read", "links:write"]
  }'
PATCH/v1/account/oauth-apps/{id}Try it
cURL
curl -X PATCH https://usebeckon.com/api/v1/account/oauth-apps/app_abc123 \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Updated App Name",
    "redirect_uris": ["https://yourapp.com/callback", "https://yourapp.com/callback2"]
  }'
DELETE/v1/account/oauth-apps/{id}Try it
cURL
curl -X DELETE https://usebeckon.com/api/v1/account/oauth-apps/app_abc123 \
  -H "Authorization: Bearer gtg_sk_xxxxxxxxxxxxxxxxxxxx"
Response
{ "data": { "deleted": true } }

Token Revocation

Revoke an access token or refresh token when it is no longer needed.

POST/api/oauth/revokeTry it
cURL
curl -X POST https://usebeckon.com/api/oauth/revoke \
  -H "Content-Type: application/json" \
  -d '{
    "token": "gtg_at_..."
  }'
Response
{ "data": { "revoked": true } }

SDKs#

JavaScript / TypeScript

Install
npm install @beckon/sdk
TypeScript
import { BeckonClient } from '@beckon/sdk';

const beckon = new BeckonClient({ apiKey: process.env.BECKON_API_KEY });

// Create a short link
const link = await beckon.links.create({
  url: 'https://example.com/long-url',
  slug: 'summer-sale',
});

console.log(link.short_url);

// List form submissions
const submissions = await beckon.forms.submissions.list('form-id', {
  status: 'unread',
  limit: 50,
});

// Verify webhook signature
import { constructEvent } from '@beckon/sdk';

const event = constructEvent(
  rawBody,
  request.headers.get('Gtg-Signature')!,
  process.env.BECKON_WEBHOOK_SECRET!
);

OpenAPI Specification

The full OpenAPI 3.1 specification is available at /api/openapi.json. Use it with Swagger UI, Postman, or any OpenAPI-compatible tool to explore the API interactively or generate client libraries in any language.

Fetch the spec
curl https://usebeckon.com/api/openapi.json

Ready to build?

Create your free account, generate an API key, and start shipping in minutes. No credit card required.