Every API here is available over the APIs.io API and to AI agents over MCP.
openapi: 3.2.0
info:
contact:
name: Linkbreakers Support
url: https://app.linkbreakers.com
description: 'This is a documentation of all the APIs of Linkbreakers
## Entry points
`GET https://api.linkbreakers.com/` and `GET https://api.linkbreakers.com/v1` answer without credentials with the API''s name, version and links. This document is served at `https://api.linkbreakers.com/openapi.json`.
## Rate limits
Every response describes where the caller stands in the IETF `RateLimit-Policy` and `RateLimit` header fields (draft-ietf-httpapi-ratelimit-headers), and in `RateLimit-Limit`, `RateLimit-Remaining`, `RateLimit-Reset` and `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset` (a Unix timestamp) for clients that read those. A request past the limit gets `429 Too Many Requests` with `Retry-After` in seconds.
- Workspace API token: 720 requests per 60 seconds, per token.
- Dashboard session or OAuth token: 600 requests per 60 seconds, per token.
- No credentials: 300 requests per 60 seconds, per client IP.
Each plan also includes a number of API calls per billing cycle. Past it, calls answer `429` with the code `MAX_PUBLIC_API_QUERIED_REACHED` until the cycle renews or the plan changes.
## Pagination
Every list pages with opaque cursors (AIP-158). Pass `pageSize`, then send the `nextPageToken` of each response back as `pageToken` (or its alias `cursor`) to get the next page. An empty or absent `nextPageToken` means the list is complete. Each list operation describes this in `x-pagination`.
## Batches and background jobs
`POST /v1/links/bulk` creates up to 250 links in one transactional request; `POST /v1/links/batch` takes the same links as a bare JSON array. `POST /v1/links/bulk/jobs` accepts the same batch and answers `202 Accepted` at once with a job and a `Location` header; poll `GET /v1/jobs/{id}` until `status` is `JOB_STATUS_SUCCEEDED` (the created link ids are in `linksBulkCreate.linkIds`) or `JOB_STATUS_FAILED` (`error` says why, and nothing was created). Jobs can be read for 24 hours after they finish.
## Versioning and deprecation
The version is in the path: every operation lives under `/v1`. Within a version, changes are additive only: new operations, new optional request fields, new response fields and new enum values. Clients should ignore fields and enum values they do not know. Anything that would break an existing client ships under a new path version instead.
An operation is retired in two steps. First it is deprecated: it keeps working, is flagged `deprecated: true` in this document, and every response carries a `Deprecation` header field (RFC 9745) with the time it was deprecated and a `Link` with `rel="deprecation"` to the policy. Then, at least 180 days later, it may be removed; that date is announced in advance in a `Sunset` header field (RFC 8594) and as `x-sunset` on the operation. The full policy: https://linkbreakers.com/help/article/api-versioning-and-deprecation-policy
## Idempotent retries
Every POST, PUT and PATCH accepts an optional `Idempotency-Key` header (draft-ietf-httpapi-idempotency-key-header). Send a new unique value, such as a UUID, with each logical request and reuse it only to retry that request. A retry with the same key and the same request returns the first response, marked `Idempotent-Replayed: true`, instead of running again. Keys are scoped to the token and kept for 24 hours. The same key with a different request is refused with `422`, and a retry while the first request is still running gets `409` with `Retry-After`. Server errors (5xx) and refusals such as 401, 403 and 429 are not stored, so retrying them runs the request again.'
title: Linkbreakers Workspace Metrics API
version: 1.185.0
x-api-versioning:
compatibility: additive changes only within a version
currentVersion: v1
deprecationHeaders:
- Deprecation
- Sunset
- Link
minimumNoticeDays: 180
policy: https://linkbreakers.com/help/article/api-versioning-and-deprecation-policy
strategy: url-path
servers:
- url: https://api.linkbreakers.com
security:
- bearerAuth: []
tags:
- description: Endpoints for analyzing workspace activity within Linkbreakers, covering rolling event totals, audience reach, and calendar heatmaps.
name: Workspace Metrics
paths:
/v1/metrics/events:
get:
description: 'Retrieve aggregated event analytics for the provided time window and optional link filter.
Requires the `analytics:read` scope.'
operationId: MetricsService_GetEventsMetric
parameters:
- description: Inclusive start timestamp for the aggregation
in: query
name: startDate
required: false
schema:
format: date-time
type: string
- description: Inclusive end timestamp for the aggregation
in: query
name: endDate
required: false
schema:
format: date-time
type: string
- description: 'Optional link filter (UUID); when omitted aggregates workspace-wide
UUID format'
in: query
name: linkId
required: false
schema:
type: string
- description: 'Optional directory filter (UUID): the links of this directory and of every
directory below it. Send link_id or directory_id, not both; when both are
omitted aggregates workspace-wide'
in: query
name: directoryId
required: false
schema:
type: string
- description: 'Optional tag filter (UUID): every link carrying this tag. Send at most one
of link_id, directory_id and tag_id'
in: query
name: tagId
required: false
schema:
type: string
- description: 'Optional country filter: visits from any of these countries (ISO 3166-1
alpha-2 codes, e.g. "FR"). Combines with the link, directory or tag filter'
explode: true
in: query
name: countries
required: false
schema:
items:
type: string
type: array
style: form
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/EventsMetric'
description: Everything worked as expected.
headers:
RateLimit:
$ref: '#/components/headers/RateLimit'
RateLimit-Policy:
$ref: '#/components/headers/RateLimit-Policy'
RateLimit-Remaining:
$ref: '#/components/headers/RateLimit-Remaining'
'429':
$ref: '#/components/responses/TooManyRequests'
default:
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unexpected error
headers:
RateLimit:
$ref: '#/components/headers/RateLimit'
RateLimit-Policy:
$ref: '#/components/headers/RateLimit-Policy'
RateLimit-Remaining:
$ref: '#/components/headers/RateLimit-Remaining'
security:
- bearerAuth:
- analytics:read
- oauth2:
- analytics:read
summary: Get events metric
tags:
- Workspace Metrics
x-required-scope: analytics:read
/v1/metrics/workspace:
get:
description: 'Return high-level workspace totals covering members, links, and activity volume.
Requires the `analytics:read` scope.'
operationId: MetricsService_GetWorkspaceMetric
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/WorkspaceMetric'
description: Everything worked as expected.
headers:
RateLimit:
$ref: '#/components/headers/RateLimit'
RateLimit-Policy:
$ref: '#/components/headers/RateLimit-Policy'
RateLimit-Remaining:
$ref: '#/components/headers/RateLimit-Remaining'
'429':
$ref: '#/components/responses/TooManyRequests'
default:
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unexpected error
headers:
RateLimit:
$ref: '#/components/headers/RateLimit'
RateLimit-Policy:
$ref: '#/components/headers/RateLimit-Policy'
RateLimit-Remaining:
$ref: '#/components/headers/RateLimit-Remaining'
security:
- bearerAuth:
- analytics:read
- oauth2:
- analytics:read
summary: Get workspace metric
tags:
- Workspace Metrics
x-required-scope: analytics:read
/v1/metrics/workspace/insight:
get:
description: 'Return workspace usage insights including the preferred link type based on historical link creation patterns.
Requires the `analytics:read` scope.'
operationId: MetricsService_GetWorkspaceInsight
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/WorkspaceInsight'
description: Everything worked as expected.
headers:
RateLimit:
$ref: '#/components/headers/RateLimit'
RateLimit-Policy:
$ref: '#/components/headers/RateLimit-Policy'
RateLimit-Remaining:
$ref: '#/components/headers/RateLimit-Remaining'
'429':
$ref: '#/components/responses/TooManyRequests'
default:
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unexpected error
headers:
RateLimit:
$ref: '#/components/headers/RateLimit'
RateLimit-Policy:
$ref: '#/components/headers/RateLimit-Policy'
RateLimit-Remaining:
$ref: '#/components/headers/RateLimit-Remaining'
security:
- bearerAuth:
- analytics:read
- oauth2:
- analytics:read
summary: Get workspace insight
tags:
- Workspace Metrics
x-required-scope: analytics:read
components:
headers:
X-RateLimit-Reset:
description: Unix time, in seconds, at which the current window resets.
schema:
example: 1791650400
type: integer
RateLimit-Reset:
description: Seconds until the current window resets.
schema:
example: 42
type: integer
RateLimit-Policy:
description: 'The quota that applies to this caller, as a structured field: `"<name>";q=<requests>;w=<window seconds>` (draft-ietf-httpapi-ratelimit-headers).'
schema:
example: '"token";q=600;w=60'
type: string
RateLimit-Limit:
description: Requests allowed in the current window.
schema:
example: 600
type: integer
X-RateLimit-Limit:
description: Same as RateLimit-Limit, for clients that read the X- convention.
schema:
example: 600
type: integer
RateLimit-Remaining:
description: Requests left in the current window.
schema:
example: 598
type: integer
RateLimit:
description: 'What is left of the quota: `"<name>";r=<remaining requests>;t=<seconds until the window resets>` (draft-ietf-httpapi-ratelimit-headers).'
schema:
example: '"token";r=598;t=42'
type: string
Retry-After:
description: Seconds to wait before retrying a refused request.
schema:
example: 42
type: integer
X-RateLimit-Remaining:
description: Same as RateLimit-Remaining, for clients that read the X- convention.
schema:
example: 598
type: integer
schemas:
ErrorResponse:
properties:
code:
description: HTTP status code
format: int32
type: integer
codeType:
default: UNKNOWN
description: Custom error code type
type: string
details:
description: Additional error details
items:
type: object
type: array
message:
description: Error message
type: string
required:
- code
- codeType
- message
- details
type: object
EventsMetric:
description: Aggregated analytics calculated on demand for time windows, giving Linkbreakers UIs headline numbers without exposing raw events.
properties:
firstAt:
format: date-time
title: Timestamp of the first event in the aggregated range
type: string
lastAt:
format: date-time
title: Timestamp of the last event in the aggregated range
type: string
topCity:
title: The top city
type: string
topCountry:
title: The top country (ISO code or name)
type: string
topDeviceType:
description: "DeviceType represents the physical form factor of the device.\nThis describes the hardware category (phone, tablet, laptop, etc.),\nNOT who or what is operating it — see DeviceActor for that.\n\n - DEVICE_TYPE_UNSPECIFIED: Device type not specified or not yet detected\n - DEVICE_TYPE_NATIVE: Native QR scanner (no browser capabilities reported)\n - DEVICE_TYPE_MOBILE: Mobile handset browser\n - DEVICE_TYPE_TABLET: Tablet browser\n - DEVICE_TYPE_DESKTOP: Desktop or laptop browser\n - DEVICE_TYPE_UNKNOWN: Unable to classify the device"
enum:
- DEVICE_TYPE_UNSPECIFIED
- DEVICE_TYPE_NATIVE
- DEVICE_TYPE_MOBILE
- DEVICE_TYPE_TABLET
- DEVICE_TYPE_DESKTOP
- DEVICE_TYPE_UNKNOWN
example: DEVICE_TYPE_DESKTOP
title: The top device type
totalCities:
format: int32
title: Total number of unique cities seen in the events
type: integer
totalCountries:
format: int32
title: Total number of unique countries seen in the events
type: integer
totalDeviceTypes:
format: int32
title: Number of unique device types
type: integer
totalEvents:
format: int32
title: Total number of events matching the query window
type: integer
title: EventsMetric
type: object
WorkspaceMetric:
description: Snapshot of high-level counters Linkbreakers surfaces on the dashboard so teams can track workspace growth at a glance.
properties:
tokenCreditsLimit:
format: int32
title: Monthly platform credits limit for the current cycle (0 means unlimited)
type: integer
tokenCreditsUsed:
format: int32
title: Monthly platform credits consumed in the current cycle
type: integer
topupCreditsLimit:
format: int32
title: Top-up credits total purchased (available = limit - used)
type: integer
topupCreditsUsed:
format: int32
title: Top-up credits consumed (from purchased credit packs)
type: integer
totalDirectories:
format: int32
title: Total number of directories (including subdirectories) in the workspace
type: integer
totalEvents:
format: int32
title: Historical count of events generated by the workspace
type: integer
totalLinks:
format: int32
title: Number of short links created within the workspace
type: integer
totalMembers:
format: int32
title: Total number of active members in the workspace
type: integer
totalMonthlyEvents:
format: int32
title: Events created within the current rolling month window
type: integer
totalPageThemeTemplates:
format: int32
title: Number of page theme templates owned by the workspace
type: integer
totalQrcodeTemplates:
format: int32
title: Number of QR code templates owned by the workspace
type: integer
title: WorkspaceMetric
type: object
WorkspaceInsight:
description: 'Derived workspace usage insight that helps the UI pre-select the right link type when creating new links.
Results are cached in Redis and refreshed on every successful link creation.'
properties:
preferredLinkType:
$ref: '#/components/schemas/PreferredLinkType'
title: The dominant link type used by the workspace
title: WorkspaceInsight
type: object
PreferredLinkType:
default: PREFERRED_LINK_TYPE_URL
description: "PreferredLinkType indicates the dominant link creation pattern for a workspace.\n\n - PREFERRED_LINK_TYPE_URL: Default when no links exist yet — treated as URL\n - PREFERRED_LINK_TYPE_CONTACT_CARD: Workspace primarily creates contact card links\n - PREFERRED_LINK_TYPE_SOCIAL_LINKS_PAGE: Workspace primarily creates social links pages\n - PREFERRED_LINK_TYPE_MIX: Workspace uses a mix of different link types\n - PREFERRED_LINK_TYPE_OPEN_MEDIA: Workspace primarily creates links that hand out media (OPEN_MEDIA exit step)"
enum:
- PREFERRED_LINK_TYPE_URL
- PREFERRED_LINK_TYPE_CONTACT_CARD
- PREFERRED_LINK_TYPE_SOCIAL_LINKS_PAGE
- PREFERRED_LINK_TYPE_MIX
- PREFERRED_LINK_TYPE_OPEN_MEDIA
type: string
responses:
TooManyRequests:
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Too many requests. Wait the number of seconds in Retry-After, or until the RateLimit window resets, then retry.
headers:
RateLimit:
$ref: '#/components/headers/RateLimit'
RateLimit-Limit:
$ref: '#/components/headers/RateLimit-Limit'
RateLimit-Policy:
$ref: '#/components/headers/RateLimit-Policy'
RateLimit-Remaining:
$ref: '#/components/headers/RateLimit-Remaining'
RateLimit-Reset:
$ref: '#/components/headers/RateLimit-Reset'
Retry-After:
$ref: '#/components/headers/Retry-After'
X-RateLimit-Limit:
$ref: '#/components/headers/X-RateLimit-Limit'
X-RateLimit-Remaining:
$ref: '#/components/headers/X-RateLimit-Remaining'
X-RateLimit-Reset:
$ref: '#/components/headers/X-RateLimit-Reset'
securitySchemes:
bearerAuth:
bearerFormat: JWT
description: JWT Bearer token authentication. Use a workspace API token obtained from the Linkbreakers dashboard. When using the SDK, pass this token to the `accessToken` field in the Configuration constructor (not `apiKey`). A token has full access or a list of scopes; each operation lists the one scope it requires, and a write scope also grants the read scope of the same resource. GET /v1/api-scopes lists every scope.
scheme: bearer
type: http
oauth2:
description: OAuth 2.0 authorization code flow with PKCE and dynamic client registration. Request only the scopes you need. The scope names are the same ones workspace API tokens hold.
flows:
authorizationCode:
authorizationUrl: https://mcp.linkbreakers.com/oauth/authorize
refreshUrl: https://mcp.linkbreakers.com/oauth/token
scopes:
analytics:read: Read events, metrics, time series, analytics data and dashboards.
analytics:write: Create, update and delete analytics dashboards and generate widget summaries.
assistant:read: Read the Assistant conversation.
assistant:write: Send files to the Assistant, clear the conversation and contact support.
billing:write: Open checkout, credit top-up and billing portal sessions.
domains:read: Read custom domains and their DNS instructions.
domains:write: Add, verify, update and delete custom domains.
integrations:read: Read the Slack and Google Forms integrations.
integrations:write: Connect, configure, test, sync and disconnect the Slack and Google Forms integrations.
links:read: Read links, their QR code images, tags, folders and link settings.
links:write: Create, update and delete links, tags, folders and link settings.
mcp:tools: Full access, including scopes added later.
media:read: Read uploaded media.
media:write: Upload and delete media.
members:read: Read workspace members.
members:write: Update, revoke, sign out and remove members. Inviting a member or changing a sign-in email or password needs full access.
page_themes:read: Read page themes and page theme templates.
page_themes:write: Change page themes and create, publish and delete page theme templates.
qrcodes:read: Read QR code designs and QR code templates.
qrcodes:write: Change QR code designs and create, publish and delete QR code templates.
tokens:read: Read API tokens and their scopes, never their secrets.
tokens:write: Create, update and delete API tokens, limited to the scopes the calling token holds.
visitors:read: Read and search visitors and their attributes.
visitors:write: Identify, update and delete visitors and their attributes.
webhooks:read: Read webhooks.
webhooks:write: Create, update and delete webhooks.
workflows:read: Read the workflow steps behind a link and validate them.
workflows:write: Create, connect, update, lay out and delete workflow steps.
workspace:read: Read the workspace and its settings.
workspace:write: Update the workspace, request enrollment and delete the workspace.
tokenUrl: https://mcp.linkbreakers.com/oauth/token
type: oauth2