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 Directories 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 managing directories in Linkbreakers. Directories let you organize links and other directories into a hierarchical folder structure.
name: Directories
paths:
/v1/directories:
get:
description: 'List directories in the workspace with optional filtering by parent directory, search, and pagination.
Requires the `links:read` scope.'
operationId: DirectoriesService_List
parameters:
- description: The maximum number of directories to return
in: query
name: pageSize
required: true
schema:
format: int64
type: integer
- description: 'The token for retrieving the next page of results
If not provided, the first page of results will be returned'
in: query
name: pageToken
required: false
schema:
type: string
- description: Filter directories by parent. When empty, returns root-level directories.
in: query
name: parentDirectoryId
required: false
schema:
type: string
- description: 'Search query to filter directories by name
Search query to filter directories by name'
in: query
name: search
required: false
schema:
type: string
- description: 'When listing with parent_directory_id, also include root-level directories if true
When listing with parent_directory_id, also include root-level directories.'
in: query
name: includeRoot
required: false
schema:
type: boolean
- description: 'When true, returns all directories recursively regardless of parent filter
Useful for getting a complete flat list of all directories in the workspace (e.g., for directory pickers)
When false (default), returns only immediate children based on parent_directory_id
Return all directories recursively. When true with empty parent_directory_id, returns all directories in workspace. When true with parent_directory_id set, returns all descendants of that directory.'
in: query
name: recursive
required: false
schema:
type: boolean
- description: Opaque cursor from the previous page's nextPageToken. Same as pageToken; when both are sent, pageToken wins.
in: query
name: cursor
required: false
schema:
type: string
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/ListDirectoriesResponse'
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:
- links:read
- oauth2:
- links:read
summary: List directories
tags:
- Directories
x-pagination:
cursorAlias: cursor
cursorParam: pageToken
endOfList: nextPageToken is empty or absent
nextCursorField: nextPageToken
pageSizeParam: pageSize
type: cursor
x-required-scope: links:read
post:
description: 'Create a new directory in the workspace. Optionally nest it under an existing directory.
Requires the `links:write` scope.'
operationId: DirectoriesService_Create
parameters:
- description: Makes retrying this request safe. See components.parameters.IdempotencyKey.
in: header
name: Idempotency-Key
required: false
schema:
maxLength: 255
minLength: 1
type: string
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/CreateDirectoryRequest'
required: true
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/CreateDirectoryResponse'
description: Everything worked as expected.
headers:
Idempotent-Replayed:
$ref: '#/components/headers/Idempotent-Replayed'
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:
- links:write
- oauth2:
- links:write
summary: Create a directory
tags:
- Directories
x-required-scope: links:write
/v1/directories/{id}:
delete:
description: 'Remove a directory from the workspace. This operation cannot be undone. A directory cannot be deleted while it still contains links or child directories; move or remove them first.
Requires the `links:write` scope.'
operationId: DirectoriesService_Delete
parameters:
- description: The ID of the directory to delete. The directory must be empty before deletion; if it still contains links or child directories, the request fails.
in: path
name: id
required: true
schema:
type: string
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/DeleteDirectoryResponse'
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'
'412':
content:
application/json:
schema: {}
description: Directory cannot be deleted because it still contains links or child directories.
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:
- links:write
- oauth2:
- links:write
summary: Delete a directory
tags:
- Directories
x-required-scope: links:write
get:
description: 'Retrieve a directory by its unique identifier.
Requires the `links:read` scope.'
operationId: DirectoriesService_Get
parameters:
- description: The ID of the directory to retrieve (UUID)
in: path
name: id
required: true
schema:
type: string
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/GetDirectoryResponse'
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:
- links:read
- oauth2:
- links:read
summary: Get a directory
tags:
- Directories
x-required-scope: links:read
patch:
description: 'Update a directory''s name or move it under a different parent directory.
Requires the `links:write` scope.'
operationId: DirectoriesService_Update
parameters:
- description: The ID of the directory to update (UUID)
in: path
name: id
required: true
schema:
type: string
- description: Makes retrying this request safe. See components.parameters.IdempotencyKey.
in: header
name: Idempotency-Key
required: false
schema:
maxLength: 255
minLength: 1
type: string
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/DirectoriesServiceUpdateBody'
required: true
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateDirectoryResponse'
description: Everything worked as expected.
headers:
Idempotent-Replayed:
$ref: '#/components/headers/Idempotent-Replayed'
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:
- links:write
- oauth2:
- links:write
summary: Update a directory
tags:
- Directories
x-required-scope: links:write
components:
schemas:
CreateDirectoryResponse:
properties:
directory:
$ref: '#/components/schemas/Directory'
title: Response containing the created directory
type: object
UpdateDirectoryResponse:
properties:
directory:
$ref: '#/components/schemas/Directory'
title: Response containing the updated directory
type: object
DirectoriesServiceUpdateBody:
properties:
name:
example: My Updated Directory
title: The new name of the directory
type: string
parentDirectoryId:
example: a1b2c3d4-e5f6-7890-abcd-ef1234567890
title: The ID of the parent directory to move this directory under (UUID)
type: string
parentDirectoryIdDelete:
title: 'Move the directory to root level by removing its parent
If true, the parent_directory_id will be set to null'
type: boolean
title: Request to update a directory
type: object
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
CreateDirectoryRequest:
properties:
name:
description: The name of the directory. This field is required.
example: My Directory
title: The name of the directory (required)
type: string
parentDirectoryId:
description: 'The ID of the parent directory (UUID)
If not provided, the directory will be created at the root level.'
example: a1b2c3d4-e5f6-7890-abcd-ef1234567890
type: string
required:
- name
title: Request to create a new directory
type: object
DeleteDirectoryResponse:
title: Response for directory deletion
type: object
GetDirectoryResponse:
properties:
directory:
$ref: '#/components/schemas/Directory'
title: Response containing the directory details
type: object
Directory:
description: 'An organizational bucket that groups links and other directories into a hierarchical folder structure
within a workspace.'
externalDocs:
description: Learn more about directories in Linkbreakers.
url: https://linkbreakers.com/help/article/what-is-a-directory-in-linkbreakers
properties:
createdAt:
format: date-time
readOnly: true
title: When the directory was created
type: string
id:
example: d87a9b30-5c8b-4d4e-9fd3-5f5f5f5f5f5f
title: The unique identifier of the directory (UUID)
type: string
name:
title: The name of the directory
type: string
parentDirectoryId:
description: 'The ID of the parent directory (UUID)
If not set, the directory is at the root level.'
example: a1b2c3d4-e5f6-7890-abcd-ef1234567890
type: string
path:
description: Full hierarchical path separated by slashes, computed server-side
example: marketing/campaigns/summer-2024
readOnly: true
type: string
updatedAt:
format: date-time
readOnly: true
title: When the directory was last updated
type: string
workspaceId:
example: c0d3cafe-5b1e-4d42-a6fd-0c5f5c3962d0
title: The workspace ID the directory belongs to (UUID)
type: string
title: Directory
type: object
ListDirectoriesResponse:
properties:
directories:
items:
$ref: '#/components/schemas/Directory'
type: object
title: The list of directories matching the filter criteria
type: array
nextPageToken:
description: Cursor to continue listing directories
example: eyJkaXJlY3RvcnlJZCI6IjEwIn0=
title: Token for retrieving the next page of results
type: string
totalCount:
description: 'How many records exist in total, so a client can tell a complete answer
from a page of one. A local-first client reads absence from this list as
deletion, and may only do so when the count it was given matches what it
received: without that, one page would look like the whole model and
everything beyond it would be removed locally.'
format: int64
type: integer
title: Response containing a list of directories
type: object
headers:
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-Reset:
description: Unix time, in seconds, at which the current window resets.
schema:
example: 1791650400
type: integer
RateLimit-Limit:
description: Requests allowed in the current window.
schema:
example: 600
type: integer
X-RateLimit-Remaining:
description: Same as RateLimit-Remaining, for clients that read the X- convention.
schema:
example: 598
type: integer
RateLimit-Reset:
description: Seconds until the current window resets.
schema:
example: 42
type: integer
Idempotent-Replayed:
description: true when this response is the stored answer to an earlier request with the same Idempotency-Key.
schema:
type: boolean
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
X-RateLimit-Limit:
description: Same as RateLimit-Limit, for clients that read the X- convention.
schema:
example: 600
type: integer
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