Skip to main content

Tourfold API (2.0.0)

Download OpenAPI specification:Download

Tourfold API Support: support@tourfold.com URL: https://docs.tourfold.com/docs/api/ License: MIT

Tourfold is a comprehensive SaaS platform for field service management. Our API provides programmatic access to manage jobs, tours, users and much more.

Use the endpoints documented here to automate dispatching flows, synchronize your account data, and build custom integrations for your operators and mobile clients.

Request and response examples follow Alpine Facility Services GmbH, a fictional Vienna maintenance company. The example identities are illustrative and are not created automatically in customer workspaces.

For detailed documentation, workflow guides, and onboarding support, visit https://docs.tourfold.com.

Billing Profile

Tenant billing profile API

Get billing profile

Returns the tenant billing profile used for invoices and Stripe customer metadata.

Authorizations:
BearerAuth

Responses

Response samples

Content type
application/json

AlpineBillingProfile

{
  • "billing_full_name": "Mara Berger",
  • "billing_business_name": "Alpine Facility Services GmbH",
  • "billing_vat_number": "ATU12345678",
  • "billing_country_code": "AT",
  • "billing_email": "billing@example.invalid",
  • "billing_address_line1": "Riverside Office 17",
  • "billing_city": "Vienna",
  • "billing_postal_code": "1210",
  • "billing_state_province": "Vienna",
  • "lock_version": 0
}

Update the billing profile

JSON Merge Patch (RFC 7386): omitted fields remain unchanged; a field set to null is cleared. Fields required for invoicing (billing_email, billing_address_line1, billing_city, billing_postal_code, billing_country_code, and a full name or business name) cannot be cleared — explicit null on those is rejected with 422. Updates the tenant billing profile and syncs supported fields to Stripe when the tenant has a Stripe customer.

Authorizations:
BearerAuth
Request Body schema: application/merge-patch+json
required
billing_full_name
string or null

Billing contact full name. Omitted leaves the value unchanged; explicit null clears it, but a business name must then be present (a full name or business name is required for invoicing).

billing_business_name
string or null

Billing business name. Omitted leaves the value unchanged; explicit null clears it, but a full name must then be present (a full name or business name is required for invoicing).

billing_vat_number
string or null

VAT number. Read-only after signup — contact support to change. Omitted leaves the value unchanged; explicit null clears it.

billing_country_code
string or null

ISO 3166-1 alpha-2 billing country code. Read-only after signup — contact support to change. Required for invoicing: omitted leaves the value unchanged; explicit null is rejected with 422.

billing_email
string or null

Email address that receives PDF invoices. Required for invoicing: omitted leaves the value unchanged; explicit null is rejected with 422.

billing_address_line1
string or null

Street address, first line. Required for invoicing: omitted leaves the value unchanged; explicit null is rejected with 422.

billing_address_line2
string or null

Street address, second line. Omitted leaves the value unchanged; explicit null clears it.

billing_city
string or null

City. Required for invoicing: omitted leaves the value unchanged; explicit null is rejected with 422.

billing_postal_code
string or null

Postal code. Required for invoicing: omitted leaves the value unchanged; explicit null is rejected with 422.

billing_state_province
string or null

State / province / region. Omitted leaves the value unchanged; explicit null clears it.

lock_version
integer or null <int64>

Optimistic-locking version: validated when provided (409 on mismatch) if a profile already exists; omitting it skips the concurrency check. Ignored when creating the first profile.

Responses

Request samples

Content type
application/merge-patch+json

UpdateBillingProfileNull

{
  • "billing_address_line2": null,
  • "billing_city": "Vienna",
  • "lock_version": 0
}

Response samples

Content type
application/json

UpdatedAlpineBillingProfile

{
  • "billing_full_name": "Mara Berger",
  • "billing_business_name": "Alpine Facility Services GmbH",
  • "billing_vat_number": "ATU12345678",
  • "billing_country_code": "AT",
  • "billing_email": "billing@example.invalid",
  • "billing_address_line1": "Riverside Office 17",
  • "billing_city": "Vienna",
  • "billing_postal_code": "1210",
  • "billing_state_province": "Vienna",
  • "lock_version": 0
}

Tags

Tag management API

List tags

Returns a paginated list of tags. Available to all authenticated users.

Authorizations:
BearerAuth
query Parameters
page
integer >= 0
Default: 0

Page number (0-based).

size
integer [ 1 .. 100 ]
Default: 20
Example: size=20

Number of items per page (max 100).

Responses

Response samples

Content type
application/json

AlpineTagsPage

{
  • "items": [
    ],
  • "page": {
    }
}

Create a tag

Creates a new tag. Requires 'tags:update' grant.

Authorizations:
BearerAuth
Request Body schema: application/json
required
name
required
string non-empty

Tag name

color
required
string non-empty

Tag color (hex or CSS color value)

Responses

Request samples

Content type
application/json

CreateUrgentTag

{
  • "name": "urgent",
  • "color": "#D92D20"
}

Response samples

Content type
application/json

CreatedUrgentTag

{
  • "id": "00000000-0000-4000-8000-000000005001",
  • "name": "urgent",
  • "color": "#D92D20",
  • "created_at": "2026-08-20T08:15:00Z",
  • "updated_at": "2026-08-20T08:15:00Z",
  • "lock_version": 0,
  • "usage_count": 1
}

Get a tag

Returns a single tag by its ID. Available to all authenticated users.

Authorizations:
BearerAuth
path Parameters
tag_id
required
string <uuid>

UUID of the tag.

Responses

Response samples

Content type
application/json

UrgentTag

{
  • "id": "00000000-0000-4000-8000-000000005001",
  • "name": "urgent",
  • "color": "#D92D20",
  • "created_at": "2026-08-20T08:15:00Z",
  • "updated_at": "2026-08-20T08:15:00Z",
  • "lock_version": 0,
  • "usage_count": 1
}

Delete a tag

Deletes a tag by ID. Requires 'tags:update' grant.

Authorizations:
BearerAuth
path Parameters
tag_id
required
string <uuid>

UUID of the tag.

Responses

Response samples

Content type
application/problem+json
{
  • "title": "Validation failed",
  • "status": 422,
  • "detail": "One or more fields failed validation",
  • "instance": "string",
  • "errors": [
    ],
  • "data": {
    }
}

Update a tag

Partial update: omitted fields remain unchanged. Requires 'tags:update' grant.

Authorizations:
BearerAuth
path Parameters
tag_id
required
string <uuid>

UUID of the tag.

Request Body schema: application/merge-patch+json
required
name
string

Tag name. Omit to leave the value unchanged. Must not be null or blank.

color
string

Tag color (hex or CSS color value). Omit to leave the value unchanged. Must not be null or blank.

lock_version
integer or null <int64>

Optimistic lock version. If provided, the update will fail with 409 if the stored version does not match.

Responses

Request samples

Content type
application/merge-patch+json

UpdateUrgentTagColor

{
  • "color": "#B42318",
  • "lock_version": 0
}

Response samples

Content type
application/json

UpdatedUrgentTag

{
  • "id": "00000000-0000-4000-8000-000000005001",
  • "name": "urgent",
  • "color": "#B42318",
  • "created_at": "2026-08-20T08:15:00Z",
  • "updated_at": "2026-08-20T09:15:00Z",
  • "lock_version": 1,
  • "usage_count": 1
}

Users

User management API. Users can be managed through these endpoints.

Replace tags assigned to a user

Replaces the tags assigned to a user. Empty tag_ids removes all assigned tags.

Authorizations:
BearerAuth
path Parameters
user_id
required
string <uuid>

UUID of the user.

Request Body schema: application/json
required
tag_ids
required
Array of strings <uuid> unique [ items <uuid > ]

Tag IDs to assign to the user. Empty array removes all assigned tags.

lock_version
integer or null <int64>

Optimistic locking version of the user aggregate; validated when provided (409 on mismatch), omitting it skips the concurrency check

Responses

Request samples

Content type
application/json
Example

ReplaceWithUrgentTag

{
  • "tag_ids": [
    ],
  • "lock_version": 0
}

Response samples

Content type
application/json

JonasWithReplacedTags

{
  • "id": "00000000-0000-4000-8000-000000001002",
  • "email": "jonas.leitner@example.invalid",
  • "phone_number": "+436641234567",
  • "roles": [
    ],
  • "skills": [
    ],
  • "firstname": "Jonas",
  • "lastname": "Leitner",
  • "created_at": "2026-08-20T08:05:00Z",
  • "updated_at": "2026-08-20T08:05:00Z",
  • "status": "ACTIVE",
  • "lock_version": 0,
  • "can_resend_set_password_email": false,
  • "tags": [
    ]
}

List skills assigned to a user

Returns the skills assigned to a user.

Authorizations:
BearerAuth
path Parameters
user_id
required
string <uuid>
Example: 1ec2dffe-2a5b-4c59-9ea2-9f0c3c5ab5af

UUID of the user whose skills should be retrieved

Responses

Response samples

Content type
application/json

JonasSkills

{
  • "items": [
    ]
}

Replace skills assigned to a user

Replaces the skills assigned to a user. Empty skill_ids removes all assigned skills.

Authorizations:
BearerAuth
path Parameters
user_id
required
string <uuid>

UUID of the user.

Request Body schema: application/json
required
skill_ids
required
Array of strings <uuid> unique [ items <uuid > ]

Skill IDs to assign to the user. Empty array removes all assigned skills.

lock_version
integer or null <int64>

Optimistic locking version of the user aggregate; validated when provided (409 on mismatch), omitting it skips the concurrency check

Responses

Request samples

Content type
application/json
Example

ReplaceWithHvacSkill

{
  • "skill_ids": [
    ],
  • "lock_version": 0
}

Response samples

Content type
application/json

JonasWithReplacedSkills

{
  • "id": "00000000-0000-4000-8000-000000001002",
  • "email": "jonas.leitner@example.invalid",
  • "phone_number": "+436641234567",
  • "roles": [
    ],
  • "skills": [
    ],
  • "firstname": "Jonas",
  • "lastname": "Leitner",
  • "created_at": "2026-08-20T08:05:00Z",
  • "updated_at": "2026-08-20T08:05:00Z",
  • "status": "ACTIVE",
  • "lock_version": 0,
  • "can_resend_set_password_email": false,
  • "tags": [
    ]
}

List users

Returns a paginated list of users in your account. Service accounts and API-only users are excluded.

Authorizations:
BearerAuth
query Parameters
page
integer >= 0
Default: 0

Page number (0-based).

size
integer [ 1 .. 100 ]
Default: 20
Example: size=20

Number of items per page (max 100).

sort
Array of strings
Example: sort=last_name:asc

Repeated sorting criteria in field:direction format. Allowed fields: id, email, first_name, last_name, status, created_at, updated_at. Default: created_at:desc.

search
string

Search term for email, first name, or last name.

role
string
Example: role=driver

Filter by role name. Matching is case-insensitive.

status
string
Default: "ACTIVE"
Enum: "ACTIVE" "BLOCKED" "INACTIVE" "ALL"

Filter by user status (ACTIVE, BLOCKED, INACTIVE, ALL). Default is ACTIVE.

role_ids
Array of strings <uuid> [ items <uuid > ]

Filter users by one or more role UUIDs. Only users assigned to at least one of the specified roles are returned.

skill_ids
Array of strings <uuid> [ items <uuid > ]

Filter users by one or more skill UUIDs. Only users with at least one of the specified skill offerings are returned.

tag_names
Array of strings

Filter users by tag name (OR semantics: returns users that have at least one of the given tags). Multiple values are supported. When omitted, no tag filtering is applied.

updated_from
string <date-time>
Example: updated_from=2024-01-01T00:00:00Z

Lower bound for updated_at (inclusive, RFC 3339). When combined with updated_to, restricts the result to users modified within the window — useful for incremental sync.

updated_to
string <date-time>
Example: updated_to=2024-12-31T23:59:59Z

Upper bound for updated_at (exclusive, RFC 3339). updated_from must be strictly before updated_to.

Responses

Response samples

Content type
application/json

UsersResponse

{
  • "items": [
    ],
  • "page": {
    }
}

Create a user

Creates a user and assigns the provided roles. Email is immutable after creation.

Authorizations:
BearerAuth
header Parameters
Origin
string
Request Body schema: application/json
required
email
required
string <email> non-empty

Email address of the user

firstname
required
string non-empty

First name of the user

lastname
required
string non-empty

Last name of the user

phone_number
string

International phone number. An explicit '+' country code is required; common formatting is accepted and normalized to canonical E.164. National numbers are rejected. Omit the field to leave it unset; a blank value is rejected.

role_ids
required
Array of strings <uuid> non-empty unique [ items <uuid > ]

Roles to assign to the user

skill_ids
Array of strings <uuid> unique [ items <uuid > ]

Skills to assign to the user

tag_ids
Array of strings <uuid> unique [ items <uuid > ]

Tags to assign to the user. When omitted, no tags are assigned.

Responses

Request samples

Content type
application/json

CreateAlpineTechnician

{
  • "email": "jonas.leitner@example.invalid",
  • "firstname": "Jonas",
  • "lastname": "Leitner",
  • "phone_number": "+43 664 123 45 67",
  • "role_ids": [
    ],
  • "skill_ids": [
    ],
  • "tag_ids": [
    ]
}

Response samples

Content type
application/json

CreateUserResponse

{
  • "id": "00000000-0000-4000-8000-000000001002",
  • "email": "jonas.leitner@example.invalid",
  • "phone_number": "+436641234567",
  • "roles": [
    ],
  • "skills": [
    ],
  • "firstname": "Jonas",
  • "lastname": "Leitner",
  • "created_at": "2026-08-20T08:05:00Z",
  • "updated_at": "2026-08-20T08:05:00Z",
  • "status": "ACTIVE",
  • "lock_version": 0,
  • "can_resend_set_password_email": false,
  • "tags": [
    ]
}

Unblock a user

Unblocks a user who was blocked due to failed login attempts.

Authorizations:
BearerAuth
path Parameters
user_id
required
string <uuid>
Example: 1ec2dffe-2a5b-4c59-9ea2-9f0c3c5ab5af

UUID of the user to unblock

header Parameters
Origin
string

Responses

Response samples

Content type
application/problem+json
{
  • "title": "Validation failed",
  • "status": 422,
  • "detail": "One or more fields failed validation",
  • "instance": "string",
  • "errors": [
    ],
  • "data": {
    }
}

Resend set password email

Resends the email that lets an invited user set their password.

Authorizations:
BearerAuth
path Parameters
user_id
required
string <uuid>
Example: 1ec2dffe-2a5b-4c59-9ea2-9f0c3c5ab5af

UUID of the user to receive the set-password email

header Parameters
Origin
string

Responses

Response samples

Content type
application/problem+json
{
  • "title": "Validation failed",
  • "status": 422,
  • "detail": "One or more fields failed validation",
  • "instance": "string",
  • "errors": [
    ],
  • "data": {
    }
}

Transfer tenant ownership

Transfers the owner role to the target user. Only the current owner may call this endpoint. The current owner loses owner and keeps admin.

Authorizations:
BearerAuth
path Parameters
user_id
required
string <uuid>

UUID of the user.

Responses

Response samples

Content type
application/json

TransferredOwner

{
  • "id": "00000000-0000-4000-8000-000000001002",
  • "email": "jonas.leitner@example.invalid",
  • "phone_number": "+436641234567",
  • "roles": [
    ],
  • "skills": [
    ],
  • "firstname": "Jonas",
  • "lastname": "Leitner",
  • "created_at": "2026-08-20T08:05:00Z",
  • "updated_at": "2026-08-20T08:05:00Z",
  • "status": "ACTIVE",
  • "lock_version": 0,
  • "can_resend_set_password_email": false,
  • "tags": [
    ]
}

Deactivate a user

Deactivates the user, preventing them from accessing the system.

Authorizations:
BearerAuth
path Parameters
user_id
required
string <uuid>
Example: 1ec2dffe-2a5b-4c59-9ea2-9f0c3c5ab5af

UUID of the user to deactivate

Responses

Response samples

Content type
application/json

DeactivatedUser

{
  • "id": "00000000-0000-4000-8000-000000001002",
  • "email": "jonas.leitner@example.invalid",
  • "phone_number": "+436641234567",
  • "roles": [
    ],
  • "skills": [ ],
  • "firstname": "Jonas",
  • "lastname": "Leitner",
  • "created_at": "2026-08-20T08:05:00Z",
  • "updated_at": "2026-08-20T10:00:00Z",
  • "status": "INACTIVE",
  • "lock_version": 1,
  • "can_resend_set_password_email": false,
  • "tags": [ ]
}

Activate a user

Activates the user, allowing them to access the system.

Authorizations:
BearerAuth
path Parameters
user_id
required
string <uuid>
Example: 1ec2dffe-2a5b-4c59-9ea2-9f0c3c5ab5af

UUID of the user to activate

Responses

Response samples

Content type
application/json

ActivatedUser

{
  • "id": "00000000-0000-4000-8000-000000001002",
  • "email": "jonas.leitner@example.invalid",
  • "phone_number": "+436641234567",
  • "roles": [
    ],
  • "skills": [
    ],
  • "firstname": "Jonas",
  • "lastname": "Leitner",
  • "created_at": "2026-08-20T08:05:00Z",
  • "updated_at": "2026-08-20T08:05:00Z",
  • "status": "ACTIVE",
  • "lock_version": 0,
  • "can_resend_set_password_email": false,
  • "tags": [
    ]
}

Change own password

Allows an authenticated user to change their own password by providing the current password. No email roundtrip is required. The new password must satisfy the password policy (minimum 8 characters).

Authorizations:
BearerAuth
Request Body schema: application/json
required
current_password
required
string non-empty

The user's current password. Used to authorize the password change.

new_password
required
string [ 8 .. 2147483647 ] characters

The desired new password. Must satisfy the password policy (minimum 8 characters).

Responses

Request samples

Content type
application/json

ChangeOwnPassword

{
  • "current_password": "current-password-example",
  • "new_password": "new-password-example"
}

Response samples

Content type
application/problem+json
{
  • "title": "Validation failed",
  • "status": 422,
  • "detail": "One or more fields failed validation",
  • "instance": "string",
  • "errors": [
    ],
  • "data": {
    }
}

Get a user

Returns a single user by their unique identifier.

Authorizations:
BearerAuth
path Parameters
user_id
required
string <uuid>
Example: 1ec2dffe-2a5b-4c59-9ea2-9f0c3c5ab5af

UUID of the user to retrieve

Responses

Response samples

Content type
application/json

UserResponse

{
  • "id": "00000000-0000-4000-8000-000000001002",
  • "email": "jonas.leitner@example.invalid",
  • "phone_number": "+436641234567",
  • "roles": [
    ],
  • "skills": [
    ],
  • "firstname": "Jonas",
  • "lastname": "Leitner",
  • "created_at": "2026-08-20T08:05:00Z",
  • "updated_at": "2026-08-20T08:05:00Z",
  • "status": "ACTIVE",
  • "lock_version": 0,
  • "can_resend_set_password_email": false,
  • "tags": [
    ]
}

Delete a user

Soft-deletes a user by marking the record as deleted (sets deleted_at timestamp). When anonymize=true, also anonymizes personal data (email, firstname, lastname, phone). The user will no longer appear in any API responses. Users cannot delete themselves. Users with the owner role cannot be deleted.

Authorizations:
BearerAuth
path Parameters
user_id
required
string <uuid>
Example: 1ec2dffe-2a5b-4c59-9ea2-9f0c3c5ab5af

UUID of the user to delete

query Parameters
anonymize
boolean
Example: anonymize=true

When true, anonymizes personal data (email, firstname, lastname, phone) in addition to soft-deleting

Responses

Response samples

Content type
application/problem+json
{
  • "title": "Validation failed",
  • "status": 422,
  • "detail": "One or more fields failed validation",
  • "instance": "string",
  • "errors": [
    ],
  • "data": {
    }
}

Update a user

JSON Merge Patch (RFC 7386) update of a user. Fields omitted remain unchanged, fields set to null are cleared. Email cannot be changed.

Authorizations:
BearerAuth
path Parameters
user_id
required
string <uuid>

UUID of the user.

Request Body schema: application/merge-patch+json
required
firstname
string

First name of the user. Omitted leaves the value unchanged. Required: it cannot be cleared, and null or a blank value is rejected.

lastname
string

Last name of the user. Omitted leaves the value unchanged. Required: it cannot be cleared, and null or a blank value is rejected.

phone_number
string or null

International phone number. An explicit '+' country code is required; common formatting is accepted and normalized to canonical E.164. National numbers are rejected. Omitted leaves the value unchanged; explicit null clears it; a blank value is rejected.

role_ids
Array of strings <uuid> unique [ items <uuid > ]

Roles to assign to the user. Omitted leaves the assignment unchanged; when provided it replaces the assigned roles and must contain at least one role. Explicit null and empty arrays are rejected (422).

lock_version
integer or null <int64>

Optimistic locking version of the user aggregate; validated when provided (409 on mismatch), omitting it skips the concurrency check

Responses

Request samples

Content type
application/merge-patch+json
Example

UpdateUserNull

{
  • "lock_version": 2,
  • "firstname": "Mara",
  • "phone_number": null
}

Response samples

Content type
application/json

UpdateUserResponse

{
  • "id": "00000000-0000-4000-8000-000000001002",
  • "email": "jonas.leitner@example.invalid",
  • "phone_number": "+436641234567",
  • "roles": [
    ],
  • "skills": [
    ],
  • "firstname": "Jonas",
  • "lastname": "Leitner",
  • "created_at": "2026-08-20T08:05:00Z",
  • "updated_at": "2026-08-20T08:05:00Z",
  • "status": "ACTIVE",
  • "lock_version": 0,
  • "can_resend_set_password_email": false,
  • "tags": [
    ]
}

Get current user

Returns the currently authenticated user.

Authorizations:
BearerAuth

Responses

Response samples

Content type
application/json

CurrentUserResponse

{
  • "id": "00000000-0000-4000-8000-000000001002",
  • "email": "jonas.leitner@example.invalid",
  • "phone_number": "+436641234567",
  • "roles": [
    ],
  • "skills": [
    ],
  • "firstname": "Jonas",
  • "lastname": "Leitner",
  • "created_at": "2026-08-20T08:05:00Z",
  • "updated_at": "2026-08-20T08:05:00Z",
  • "status": "ACTIVE",
  • "lock_version": 0,
  • "can_resend_set_password_email": false,
  • "tags": [
    ]
}

Skills

Skills management API

List skills

Returns a paginated list of skills.

Authorizations:
BearerAuth
query Parameters
page
integer >= 0
Default: 0

Page number (0-based).

size
integer [ 1 .. 100 ]
Default: 20
Example: size=20

Number of items per page (max 100).

sort
Array of strings
Example: sort=name:asc

Repeated sorting criteria in field:direction format. Allowed fields: id, name, skill, skill_type, short_key, created_at, updated_at. Default: name:asc.

search
string

Search term for skill, skill type, short_key, or name.

updated_from
string <date-time>

Lower bound for updated_at (inclusive, RFC 3339).

updated_to
string <date-time>

Upper bound for updated_at (exclusive, RFC 3339). Must be later than updated_from.

Responses

Response samples

Content type
application/json

SkillsResponse

{
  • "items": [
    ],
  • "page": {
    }
}

Create a skill

Creates a new skill with the provided information

Authorizations:
BearerAuth
Request Body schema: application/json
required
skill
required
string [ 0 .. 32 ] characters

Skill identifier

skill_type
required
string [ 0 .. 32 ] characters

Skill type

name
required
string [ 0 .. 255 ] characters

Skill name

short_key
required
string [ 0 .. 10 ] characters

Short key identifier

Responses

Request samples

Content type
application/json

CreateHvacMaintenanceSkill

{
  • "skill": "HVAC_MAINTENANCE",
  • "skill_type": "MAINTENANCE",
  • "name": "HVAC maintenance",
  • "short_key": "HVAC"
}

Response samples

Content type
application/json

SkillResponse

{
  • "id": "00000000-0000-4000-8000-000000006001",
  • "skill": "HVAC_MAINTENANCE",
  • "skill_type": "MAINTENANCE",
  • "name": "HVAC maintenance",
  • "short_key": "HVAC",
  • "created_at": "2026-08-20T08:12:00Z",
  • "updated_at": "2026-08-20T08:12:00Z",
  • "lock_version": 0
}

Get skill by ID

Retrieves a specific skill by its ID

Authorizations:
BearerAuth
path Parameters
skill_id
required
string <uuid>

UUID of the skill.

Responses

Response samples

Content type
application/json

SkillsResponse

{
  • "id": "00000000-0000-4000-8000-000000006001",
  • "created_at": "2026-08-20T08:12:00Z",
  • "updated_at": "2026-08-20T08:12:00Z",
  • "skill": "HVAC_MAINTENANCE",
  • "skill_type": "MAINTENANCE",
  • "name": "HVAC maintenance",
  • "short_key": "HVAC",
  • "lock_version": 0
}

Delete skill

Deletes a skill by its ID

Authorizations:
BearerAuth
path Parameters
skill_id
required
string <uuid>

UUID of the skill.

Responses

Response samples

Content type
application/problem+json
{
  • "title": "Validation failed",
  • "status": 422,
  • "detail": "One or more fields failed validation",
  • "instance": "string",
  • "errors": [
    ],
  • "data": {
    }
}

Update a skill

Partial update: omitted fields remain unchanged (JSON Merge Patch, RFC 7386).

Authorizations:
BearerAuth
path Parameters
skill_id
required
string <uuid>

UUID of the skill.

Request Body schema: application/merge-patch+json
required
skill
string

Skill identifier (max 32 characters). Omitted leaves the value unchanged; explicit null is rejected (422) — it is required and cannot be cleared.

skill_type
string

Skill type (max 32 characters). Omitted leaves the value unchanged; explicit null is rejected (422) — it is required and cannot be cleared.

name
string

Skill name (max 255 characters). Omitted leaves the value unchanged; explicit null is rejected (422) — it is required and cannot be cleared.

short_key
string

Short key identifier (max 10 characters). Omitted leaves the value unchanged; explicit null is rejected (422) — it is required and cannot be cleared.

lock_version
integer or null <int64>

Optimistic-locking version of the skill: validated when provided (409 on mismatch); omitting it skips the concurrency check

Responses

Request samples

Content type
application/merge-patch+json
Example

UpdateSkillName

{
  • "lock_version": 2,
  • "name": "Advanced HVAC maintenance"
}

Response samples

Content type
application/json

UpdateSkillResponse

{
  • "id": "00000000-0000-4000-8000-000000006001",
  • "skill": "HVAC_MAINTENANCE",
  • "skill_type": "MAINTENANCE",
  • "name": "HVAC maintenance",
  • "short_key": "HVAC",
  • "created_at": "2026-08-20T08:12:00Z",
  • "updated_at": "2026-08-20T08:12:00Z",
  • "lock_version": 0
}

Billing Invoices

Tenant billing invoice API

List billing invoices

Returns invoice summaries for Stripe-backed self-service tenants. Other plan kinds return an empty list. Stripe is the source of truth: the service fetches a bounded window of the most recent 100 invoices from Stripe and page/size paginate over that fetched window (newest first). page.total_elements therefore never exceeds 100 even if Stripe holds more history.

Authorizations:
BearerAuth
query Parameters
page
integer >= 0
Default: 0

Page number (0-based).

size
integer [ 1 .. 100 ]
Default: 20
Example: size=20

Number of items per page (max 100).

Responses

Response samples

Content type
application/json

AlpineInvoicesPage

{
  • "items": [
    ],
  • "page": {
    }
}

Get billing invoice download URL

Returns the Stripe invoice PDF URL after verifying the invoice belongs to this tenant's Stripe customer.

Authorizations:
BearerAuth
path Parameters
invoice_id
required
string

Identifier of the invoice.

Responses

Response samples

Content type
application/json

Sms Report

Query SMS message history for reporting and auditing. Returns all SMS sent through the system with status, timestamps, and gateway information.

List SMS message history

        Returns a paginated list of SMS messages for the current tenant, with optional filtering by date range and status.

        **Date Range:**
        - Defaults to last 28 days if not specified
        - Filters on the `scheduled_at` timestamp using a half-open range
        - Use RFC 3339 format (e.g., 2024-01-15T10:30:00Z)

        **Status Values:**
        - SCHEDULED: Waiting to be sent
        - SENDING: Currently being sent
        - SENT: Successfully accepted by gateway
        - DELIVERED: Confirmed delivered to recipient (Twilio only, via webhook)
        - FAILED: Failed to send

        **Sorting:**
        - Default: `scheduled_at:desc` (newest first)
        - Allowed fields: scheduled_at, sent_at, status, created_at, to_number, gateway_name
        - Format: `field:asc` or `field:desc`
        - Multiple sort criteria supported
    
Authorizations:
BearerAuth
query Parameters
scheduled_from
string <date-time>
Example: scheduled_from=2024-01-01T00:00:00Z

Lower bound for scheduled_at (inclusive, RFC 3339). Defaults to 28 days ago.

scheduled_to
string <date-time>
Example: scheduled_to=2024-12-31T23:59:59Z

Upper bound for scheduled_at (exclusive, RFC 3339). Defaults to now.

status
string
Enum: "SCHEDULED" "SENDING" "SENT" "DELIVERED" "FAILED"
Example: status=SENT

Filter by SMS status

page
integer >= 0
Default: 0

Page number (0-based).

size
integer [ 1 .. 1000 ]
Default: 100
Example: size=100

Number of items per page (max 1000). The cap is deliberately higher than the platform default of 100 because this is a report/export-style endpoint.

sort
Array of strings
Example: sort=scheduled_at:desc

Repeated sorting criteria in field:direction format. Allowed fields: id, scheduled_at, sent_at, status, created_at, to_number, from_number, gateway_name. Default: scheduled_at:desc.

Responses

Response samples

Content type
application/json

SmsReportExample

{
  • "items": [
    ],
  • "page": {
    }
}

Custom Object Relations

API for managing relations between custom object definitions

List all relations

Retrieves a paginated list of all relations in the tenant

Authorizations:
BearerAuth
query Parameters
page
integer >= 0
Default: 0

Page number (0-based).

size
integer [ 1 .. 100 ]
Default: 20
Example: size=20

Number of items per page (max 100).

Responses

Response samples

Content type
application/json

RelationsPage

{
  • "items": [
    ],
  • "page": {
    }
}

Create relations between definitions

        Creates one or more relations between custom object definitions. Each relation has two
        positional sides (`a` and `b`) — there is no inherent direction; both are stored
        symmetrically. Each side independently declares its own cardinality, required flag,
        navigation slug, and title.

        ### Cardinality convention

        `sideX.cardinality` describes **how many instances of X appear per joined instance of Y**
        (standard ERD multiplicity drawn at this side of the diamond).

        - `sideA = ONE, sideB = MANY` → one A has many B's; each B has one A (1:N).
        - `sideA = ONE, sideB = ONE`  → 1:1.
        - `sideA = MANY, sideB = MANY` → many-to-many.

        To allow "one Person writes many Books", set `book.cardinality = MANY`
        ('many books per person') and `person.cardinality = ONE` ('one person per book').
        To rejection-test this: providing multiple targets when the target side is `ONE`
        returns HTTP 422 `errorType=cardinality-violation-source`.

        ### Required convention

        Set `required=true` on the side whose **instances cannot be created without this
        relation**. Enforced at instance creation by `validateRequiredRelations` against the
        side that matches the definition being created. Missing-relation rejection surfaces as
        HTTP 422 `errorType=required-relation`.

        ### Example 1 — Person ↔ Book (1:N, Book requires an Author)

        One Person can write many Books, and a Book cannot exist without an Author.

        ```
        POST /api/v2/custom-objects/relations
        {
          "relations": [{
            "a": {
              "definition_slug": "person",
              "cardinality": "ONE",
              "required": false,
              "slug": "books",
              "title": "Books",
              "is_hidden": false,
              "translations": {"en": {"singular": "Book", "plural": "Books"}}
            },
            "b": {
              "definition_slug": "book",
              "cardinality": "MANY",
              "required": true,
              "slug": "author",
              "title": "Author",
              "is_hidden": false,
              "translations": {"en": {"singular": "Author", "plural": "Authors"}}
            }
          }]
        }
        ```

        - `b.cardinality = MANY` ⇒ each Person has many Books.
        - `a.cardinality = ONE`  ⇒ each Book has one Person.
        - `b.required = true`    ⇒ creating a Book without `author` returns 422 `required-relation`.
        - `a.required = false`   ⇒ a Person with zero Books is valid.

        The working integration analogue is `HumanCarRelationIntegrationTest`
        (`should enforce required relation on creation`, `should enforce required many relation
        as at least one association`).

        ### Example 2 — Tracker ↔ Location (1:1, Tracker requires Location)

        A tracker (e.g. a GPS device) needs a location to be useful. The location side carries
        `settings_type: "location"` which activates the additional 1:1 + location
        constraints from `LocationRelationSettingsValidator`.

        **Convention:** `location` is a built-in type — customers only ever declare it
        as an attribute on another definition, never edit it directly. So put the consuming
        custom object (here: `tracker`) on side `a` and `location` on side `b`.

        ```
        POST /api/v2/custom-objects/relations
        {
          "relations": [{
            "a": {
              "definition_slug": "tracker",
              "cardinality": "ONE",
              "required": true,
              "slug": "location",
              "title": "Location",
              "is_hidden": false,
              "translations": {"en": {"singular": "Location", "plural": "Locations"}}
            },
            "b": {
              "definition_slug": "location",
              "cardinality": "ONE",
              "required": false,
              "slug": "tracker",
              "title": "Tracker",
              "is_hidden": false,
              "translations": {"en": {"singular": "Tracker", "plural": "Trackers"}}
            },
            "settings": { "settings_type": "location", "icon_file_id": null }
          }]
        }
        ```

        - Both sides `cardinality = ONE` ⇒ 1:1 (each tracker has one location, each location belongs to one tracker).
        - `a.required = true` on the tracker side ⇒ creating a tracker without `location` returns 422 `required-relation`.
        - `b.required = false` on the location side ⇒ a location can exist with no tracker pointing at it.
        - `settings.settings_type = "location"` ⇒ also rejects non-1:1 configurations (422
          `errorType=location-relation-must-be-one-to-one`) and rejects relations where neither
          side is `location` (422 `errorType=location-relation-must-target-property-location`).

        ### Validation summary
        - Missing required relation at instance creation → 422 `required-relation`.
        - Too many targets for a `ONE`-target relation → 422 `cardinality-violation-source`.
        - Target already linked to another source when source side is `ONE` → 422 `cardinality-violation-target`.
        - Location-specific shape errors → 400 with `location-relation-*` error types
          (see `LocationRelationCardinalityApiTest`).
    
Authorizations:
BearerAuth
Request Body schema: application/json
required
required
Array of objects (RelationSchema)

List of relations to create

Array
required
object (RelationSide)

Positional side A of the relation. No inherent meaning vs side B — pick whichever you prefer; both are stored symmetrically as side_a_* / side_b_* columns.

required
object (RelationSide)

Positional side B of the relation. No inherent meaning vs side A.

object (RelationSettings)

Custom settings attached to a relation definition. The settings_type discriminator selects the variant.

Responses

Request samples

Content type
application/json

CreateMaintenanceEquipmentRelation

{
  • "relations": [
    ]
}

Response samples

Content type
application/json

CreatedMaintenanceEquipmentRelation

{
  • "items": [
    ],
  • "page": {
    }
}

Create an association between two instances

Associates two instances via the specified relation, providing the side A and side B instance IDs

Authorizations:
BearerAuth
path Parameters
relation_id
required
string <uuid>

UUID of the custom-object relation.

Request Body schema: application/json
required
side_a_instance_id
required
string <uuid>

ID of the side A instance

side_b_instance_id
required
string <uuid>

ID of the side B instance

Responses

Request samples

Content type
application/json

AssociateRequestWithEquipment

{
  • "side_a_instance_id": "6f3d2a10-0000-4000-8000-000000000101",
  • "side_b_instance_id": "6f3d2a10-0000-4000-8000-000000000201"
}

Response samples

Content type
application/problem+json
{
  • "title": "Validation failed",
  • "status": 422,
  • "detail": "One or more fields failed validation",
  • "instance": "string",
  • "errors": [
    ],
  • "data": {
    }
}

Delete an association between two instances

Removes the association between two instances for the specified relation

Authorizations:
BearerAuth
path Parameters
relation_id
required
string <uuid>

UUID of the custom-object relation.

query Parameters
side_a_instance_id
required
string <uuid>
side_b_instance_id
required
string <uuid>

Responses

Response samples

Content type
application/problem+json
{
  • "title": "Validation failed",
  • "status": 422,
  • "detail": "One or more fields failed validation",
  • "instance": "string",
  • "errors": [
    ],
  • "data": {
    }
}

List relations of a specific definition

Retrieves a paginated list of relations for a given definition slug. Readable by users who can modify either definitions (DDL) or instances; the response carries the relation IDs needed to create instances with associations.

Authorizations:
BearerAuth
path Parameters
definition_slug
required
string

Slug of the custom-object definition.

query Parameters
page
integer >= 0
Default: 0

Page number (0-based).

size
integer [ 1 .. 100 ]
Default: 20
Example: size=20

Number of items per page (max 100).

Responses

Response samples

Content type
application/json

EquipmentRelationsPage

{
  • "items": [
    ],
  • "page": {
    }
}

Delete a relation

Deletes a relation by its ID

Authorizations:
BearerAuth
path Parameters
relation_id
required
string <uuid>

UUID of the custom-object relation.

Responses

Response samples

Content type
application/problem+json
{
  • "title": "Validation failed",
  • "status": 422,
  • "detail": "One or more fields failed validation",
  • "instance": "string",
  • "errors": [
    ],
  • "data": {
    }
}

Webhook Endpoints

Manage webhook endpoints and subscriptions

List webhook endpoints

Returns a page of webhook endpoints configured for the current tenant. Pass definition_id to return only endpoints whose stored subscription explicitly names that custom-object definition.

Authorizations:
BearerAuth
query Parameters
page
integer >= 0
Default: 0

Page number (0-based).

size
integer [ 1 .. 100 ]
Default: 20
Example: size=20

Number of items per page (max 100).

definition_id
string <uuid>
Example: definition_id=6b1e0f22-0000-4000-8000-000000000001

Return only endpoints holding a subscription scoped to this custom-object definition. Broader patterns such as * also deliver that definition's events but are not matched here, since their stored pattern does not name the definition.

Responses

Response samples

Content type
application/json

AlpineWebhookEndpointsPage

{
  • "items": [
    ],
  • "page": {
    }
}

Create a webhook endpoint

Creates a webhook endpoint with optional subscriptions and returns the generated secret once.

Authorizations:
BearerAuth
Request Body schema: application/json
required
display_name
required
string [ 1 .. 255 ] characters

Human readable endpoint name

endpoint_url
required
string <uri> [ 1 .. 2048 ] characters ^https?://.+$

HTTPS destination URL. Plain HTTP is accepted only when the server's explicit local-development escape hatch is enabled.

signature_scheme
string
Default: "HMAC_SHA256"
Value: "HMAC_SHA256"

Signature scheme

enabled
boolean
Default: true

Whether deliveries are enabled

retry
boolean
Default: true

Whether failed deliveries should be retried

subscriptions
Array of strings [ 0 .. 100 ] items [ items <= 512 characters ]

Webhook event types to subscribe to

Responses

Request samples

Content type
application/json

CreateAlpineIntegrationEndpoint

{}

Response samples

Content type
application/json

CreatedAlpineIntegrationEndpoint

{
  • "id": "00000000-0000-4000-8000-000000008001",
  • "display_name": "Alpine maintenance integration",
  • "signature_scheme": "HMAC_SHA256",
  • "enabled": true,
  • "retry": true,
  • "subscriptions": [
    ],
  • "invalid_subscriptions": [ ],
  • "created_at": "2026-08-20T08:40:00Z",
  • "updated_at": "2026-08-20T08:40:00Z",
  • "lock_version": 0,
  • "secret": "whsec_example_not_a_real_secret"
}

Rotate webhook secret

Rotates and returns a new secret. The previous secret is invalidated. The change takes effect immediately and the operation takes no request body.

Authorizations:
BearerAuth
path Parameters
endpoint_id
required
string <uuid>

UUID of the webhook endpoint.

Responses

Response samples

Content type
application/json

RotatedAlpineIntegrationSecret

{
  • "id": "00000000-0000-4000-8000-000000008001",
  • "display_name": "Alpine maintenance integration",
  • "signature_scheme": "HMAC_SHA256",
  • "enabled": true,
  • "retry": true,
  • "subscriptions": [
    ],
  • "invalid_subscriptions": [ ],
  • "created_at": "2026-08-20T08:40:00Z",
  • "updated_at": "2026-08-20T09:45:00Z",
  • "lock_version": 2,
  • "secret": "whsec_rotated_example_not_a_real_secret"
}

Get a webhook endpoint

Returns one webhook endpoint configured for the current tenant. The signing secret is never returned.

Authorizations:
BearerAuth
path Parameters
endpoint_id
required
string <uuid>

UUID of the webhook endpoint.

Responses

Response samples

Content type
application/json

AlpineIntegrationEndpoint

{
  • "id": "00000000-0000-4000-8000-000000008001",
  • "display_name": "Alpine maintenance integration",
  • "signature_scheme": "HMAC_SHA256",
  • "enabled": true,
  • "retry": true,
  • "subscriptions": [
    ],
  • "invalid_subscriptions": [ ],
  • "created_at": "2026-08-20T08:40:00Z",
  • "updated_at": "2026-08-20T08:40:00Z",
  • "lock_version": 0
}

Delete a webhook endpoint

Deletes a webhook endpoint and all its subscriptions.

Authorizations:
BearerAuth
path Parameters
endpoint_id
required
string <uuid>

UUID of the webhook endpoint.

Responses

Response samples

Content type
application/problem+json
{
  • "title": "Validation failed",
  • "status": 422,
  • "detail": "One or more fields failed validation",
  • "instance": "string",
  • "errors": [
    ],
  • "data": {
    }
}

Update a webhook endpoint

Partial update: omitted fields remain unchanged. Include subscriptions to replace them, or omit to keep existing subscriptions.

Authorizations:
BearerAuth
path Parameters
endpoint_id
required
string <uuid>

UUID of the webhook endpoint.

Request Body schema:
required
display_name
string [ 1 .. 255 ] characters

Human readable endpoint name. Omitted leaves the value unchanged. Explicit null and blank strings are rejected (422).

endpoint_url
string <uri> [ 1 .. 2048 ] characters

HTTPS destination URL. Plain HTTP is accepted only when the server's explicit local-development escape hatch is enabled. Omitted leaves the value unchanged. Explicit null and blank strings are rejected (422).

signature_scheme
string
Value: "HMAC_SHA256"

Signature scheme. Omitted leaves the value unchanged. Explicit null is rejected (422).

enabled
boolean

Whether deliveries are enabled. Omitted leaves the value unchanged. Explicit null is rejected (422).

retry
boolean

Whether failed deliveries should be retried. Omitted leaves the value unchanged. Explicit null is rejected (422).

subscriptions
Array of strings <= 100 items [ items <= 512 characters ]

Webhook event types to subscribe to. If provided, replaces all existing subscriptions. Omitted leaves the subscriptions unchanged. Explicit null is rejected (422).

lock_version
integer <int64>

Optimistic lock version: validated when provided (409 on mismatch); omitting it skips the concurrency check. Explicit null is rejected (422).

Responses

Request samples

Content type
Example

ReplaceIntegrationSubscriptions

{
  • "subscriptions": [
    ],
  • "lock_version": 0
}

Response samples

Content type
application/json

UpdatedAlpineIntegrationEndpoint

{
  • "id": "00000000-0000-4000-8000-000000008001",
  • "display_name": "Alpine maintenance integration",
  • "signature_scheme": "HMAC_SHA256",
  • "enabled": true,
  • "retry": true,
  • "subscriptions": [
    ],
  • "invalid_subscriptions": [ ],
  • "created_at": "2026-08-20T08:40:00Z",
  • "updated_at": "2026-08-20T09:40:00Z",
  • "lock_version": 1
}

Webhook Testing

Test webhook endpoint connectivity

Trigger a test webhook

Immediately delivers a test webhook to the specified endpoint to verify connectivity

Authorizations:
BearerAuth
Request Body schema: application/json
required
endpoint_id
required
string <uuid>

Endpoint id to send a test webhook to

Responses

Request samples

Content type
application/json

TestAlpineIntegrationEndpoint

{
  • "endpoint_id": "00000000-0000-4000-8000-000000008001"
}

Response samples

Content type
application/json

SuccessfulAlpineWebhookTest

{
  • "last_test_tried_at": "2026-08-20T09:50:00Z",
  • "test_was_successful": true
}

Comments

Polymorphic comments on target objects.

List comments on a target

Returns comments on the given target, paginated. sort follows the v2 <mode>:<direction> convention: threaded:desc (default — root comments newest-first; replies always oldest-first within each thread), threaded:asc, flat:desc, flat:asc. In threaded mode the page numbers refer to root comments and the response interleaves each root with its replies. Requires the comments read grant and read access to the target object.

Authorizations:
BearerAuth
query Parameters
target_type
required
string
Example: target_type=bw:case

Family-prefixed identifier of the object the comments are attached to. Examples: "co:<slug>" for custom-object instances, "bw:case" for BW cases.

target_id
required
string <uuid>
Example: target_id=22222222-2222-3333-4444-555555555555

Id of the target object the comments are attached to.

page
integer >= 0
Default: 0

Page number (0-based). In threaded mode this refers to the root-comment page.

size
integer [ 1 .. 1000 ]
Default: 20
Example: size=20

Number of root comments per page (threaded) or items per page (flat). Range 1..1000. The 1000 cap is intentionally higher than the platform default (100) because the comments list is the primary read path for moderation, audit-log, and AI-assistant scrapes — workflows that need the full thread in one shot rather than paged. Frontends paginate at 20–50; the high cap is for server-side and integration callers.

sort
string
Default: "threaded:desc"
Enum: "threaded:desc" "threaded:asc" "flat:desc" "flat:asc"
Example: sort=threaded:desc

Sort instruction in <mode>:<direction> form. Default threaded:desc.

Responses

Response samples

Content type
application/json

EquipmentCommentsPage

{
  • "items": [
    ],
  • "unread_count": 0,
  • "page": {
    }
}

Post a new comment

Creates a comment on the given target. Create access follows the target adapter for the supplied target_type. Server-side dedup: a duplicate submission by the same author against the same target with the same body within the configured window (default 60s) returns the existing comment with HTTP 200 instead of inserting a duplicate.

Both the 201 (fresh insert) and 200 (dedup) responses include a Location: /api/v2/comments/{comment_id} header pointing at the persisted row, per RFC 7231.

Authorizations:
BearerAuth
Request Body schema: application/json
required
target_type
required
string non-empty

Family-prefixed identifier of the object the comment is attached to. Examples: "co:<slug>" for custom-object instances, "bw:case" for BW cases. Each supported family is registered by a target adapter that owns existence and authorization checks.

target_id
required
string <uuid>

Id of the target object the comment is attached to.

parent_comment_id
string <uuid>

Id of the parent comment when posting a reply. Must exist and belong to the same target. Omit (or send null) to post a root comment.

body_markdown
required
string [ 1 .. 10000 ] characters

Comment body in markdown. Server enforces the v2 allow-list (bold, italic, strikethrough (GFM ~~text~~), inline code, headings level 1–3, fenced code blocks, ordered/unordered lists, blockquotes, http(s) links, inline image references via the attachment:<uuid> scheme). Headings level 4+, raw HTML, tables, plain http(s) images, and non-http(s) link schemes are rejected with comments.body-invalid-markdown.

attachment_ids
Array of strings <uuid> [ items <uuid > ]

Filestore file ids previously obtained from POST /api/v2/comments/attachments/uploads. Each id must have been used to upload a real file (upload status UPLOADED); files uploaded for other features are rejected with comments/attachment-not-from-comments. Inline references in the body via ![alt](attachment:<uuid>) must also be listed here. Position in the array becomes the chip-row order for non-inline files. Defaults to an empty array (no attachments). Capped at comments.attachments.max-per-comment (default 10) — exceeding the cap returns comments/too-many-attachments (422).

Responses

Request samples

Content type
application/json

CreateEquipmentMaintenanceComment

{
  • "target_type": "co:equipment",
  • "target_id": "6f3d2a10-0000-4000-8000-000000000101",
  • "body_markdown": "Replacement filter ordered."
}

Response samples

Content type
application/json

DeduplicatedFilterComment

{
  • "id": "00000000-0000-4000-8000-000000007501",
  • "target_type": "co:equipment",
  • "target_id": "6f3d2a10-0000-4000-8000-000000000101",
  • "root_comment_id": "00000000-0000-4000-8000-000000007501",
  • "body_markdown": "Replacement filter ordered.",
  • "author": {
    },
  • "created_at": "2026-03-03T10:45:00Z",
  • "updated_at": "2026-03-03T10:45:00Z",
  • "lock_version": 0,
  • "is_edited": false,
  • "is_moderated": false,
  • "is_deleted": false,
  • "is_deleted_by_moderator": false,
  • "is_unread": false,
  • "reactions": [ ],
  • "mentions": [ ],
  • "attachments": [ ]
}

Restore a soft-deleted comment (moderator only)

Clears the soft-delete tombstone on a comment. Always a moderator action; requires the comments:update grant. Returns 422 when the comment is not currently soft-deleted (comments.cannot-restore-not-deleted).

Authorizations:
BearerAuth
path Parameters
comment_id
required
string <uuid>
Example: 11111111-aaaa-bbbb-cccc-dddddddddddd

Id of the soft-deleted comment to restore.

Responses

Response samples

Content type
application/json

RestoredFilterComment

{
  • "id": "00000000-0000-4000-8000-000000007501",
  • "target_type": "co:equipment",
  • "target_id": "6f3d2a10-0000-4000-8000-000000000101",
  • "root_comment_id": "00000000-0000-4000-8000-000000007501",
  • "body_markdown": "Replacement filter ordered.",
  • "author": {
    },
  • "created_at": "2026-03-03T10:45:00Z",
  • "updated_at": "2026-03-03T10:45:00Z",
  • "lock_version": 0,
  • "is_edited": false,
  • "is_moderated": false,
  • "is_deleted": false,
  • "is_deleted_by_moderator": false,
  • "is_unread": false,
  • "reactions": [ ],
  • "mentions": [ ],
  • "attachments": [ ]
}

Add an emoji reaction to a comment

Adds one of Tourfold's supported emoji reactions (👍 ❤️ 😂 🎉 😮 😢 👀 🙌) by the calling user to the named comment. Idempotent: 201 on the first add, 200 on a duplicate add (no row inserted, no SSE / webhook emitted). Tombstoned comments reject reactions with comments.reaction-on-deleted-comment (422).

Authorizations:
BearerAuth
path Parameters
comment_id
required
string <uuid>
Example: 11111111-aaaa-bbbb-cccc-dddddddddddd

Id of the comment to react to.

Request Body schema: application/json
required
emoji
required
string
Enum: "👍" "❤️" "😂" "🎉" "😮" "😢" "👀" "🙌"

Emoji to react with. Supported values are 👍 ❤️ 😂 🎉 😮 😢 👀 🙌.

Responses

Request samples

Content type
application/json

AddThumbsUp

{
  • "emoji": "👍"
}

Response samples

Content type
application/json

ExistingThumbsUpReaction

{
  • "id": "00000000-0000-4000-8000-000000007501",
  • "target_type": "co:equipment",
  • "target_id": "6f3d2a10-0000-4000-8000-000000000101",
  • "root_comment_id": "00000000-0000-4000-8000-000000007501",
  • "body_markdown": "Replacement filter ordered.",
  • "author": {
    },
  • "created_at": "2026-03-03T10:45:00Z",
  • "updated_at": "2026-03-03T10:45:00Z",
  • "lock_version": 0,
  • "is_edited": false,
  • "is_moderated": false,
  • "is_deleted": false,
  • "is_deleted_by_moderator": false,
  • "is_unread": false,
  • "reactions": [
    ],
  • "mentions": [ ],
  • "attachments": [ ]
}

Mark a single comment as unread for the caller

Adds (or refreshes) the caller's unread override for the comment. The comment is then unread regardless of where the cursor sits. The cursor is not moved.

Authorizations:
BearerAuth
path Parameters
comment_id
required
string <uuid>
Example: 11111111-aaaa-bbbb-cccc-dddddddddddd

Id of the comment to mark unread.

Responses

Response samples

Content type
application/problem+json
{
  • "title": "Validation failed",
  • "status": 422,
  • "detail": "One or more fields failed validation",
  • "instance": "string",
  • "errors": [
    ],
  • "data": {
    }
}

Clear the caller's unread override on a single comment

Removes the caller's per-comment unread override, if any. Does not move the cursor. Idempotent: a no-op success when no override exists.

Authorizations:
BearerAuth
path Parameters
comment_id
required
string <uuid>
Example: 11111111-aaaa-bbbb-cccc-dddddddddddd

Id of the comment to clear the unread override on.

Responses

Response samples

Content type
application/problem+json
{
  • "title": "Validation failed",
  • "status": 422,
  • "detail": "One or more fields failed validation",
  • "instance": "string",
  • "errors": [
    ],
  • "data": {
    }
}

Advance the caller's read cursor on a target

Sets the caller's read cursor on (target_type, target_id) to the named comment (inclusive). Monotonic — naming an older comment is a no-op success returning the existing cursor. As a side effect, clears the caller's per-comment unread overrides at-or-before the new cursor.

Authorizations:
BearerAuth
Request Body schema: application/json
required
target_type
required
string non-empty

Family-prefixed identifier of the object the cursor lives on. Examples: "co:<slug>" for custom-object instances, "bw:case" for BW cases.

target_id
required
string <uuid>

Id of the target object the cursor lives on.

comment_id
required
string <uuid>

Id of the comment the cursor should advance to (inclusive). The comment must belong to the supplied (target_type, target_id) — server returns 422 (comments.read-cursor-target-mismatch) otherwise.

Responses

Request samples

Content type
application/json

MarkEquipmentCommentsRead

{
  • "target_type": "co:equipment",
  • "target_id": "6f3d2a10-0000-4000-8000-000000000101",
  • "comment_id": "00000000-0000-4000-8000-000000007501"
}

Response samples

Content type
application/json

EquipmentCommentsReadCursor

{
  • "target_type": "co:equipment",
  • "target_id": "6f3d2a10-0000-4000-8000-000000000101",
  • "last_seen_comment_id": "00000000-0000-4000-8000-000000007501",
  • "last_seen_created_at": "2026-03-03T10:45:00Z"
}

Issue a presigned form for a single comment attachment upload

Validates MIME / size / storage allowance and returns a presigned form descriptor. The client then POSTs the bytes to upload_url as multipart/form-data, including every entry from upload_fields (preserving their original order) followed by the actual file payload under the file part. The returned attachment_id is referenced later in POST /api/v2/comments (or PATCH /api/v2/comments/{comment_id}) via the attachment_ids array. No so_comment_attachments row is created at this point — files uploaded but never referenced are reaped asynchronously by the orphan-cleanup cron. Status is 200, not 201, because no addressable resource is exposed at a Location URL: the attachment_id is only meaningful once a subsequent comment create/edit references it. Requires the comments:create grant.

Not exposed via MCP — agents can't fill in presigned forms; the comments_create and comments_update MCP tools strip any attachment_ids from incoming payloads.

Authorizations:
BearerAuth
Request Body schema: application/json
required
original_file_name
required
string [ 0 .. 255 ] characters

Original filename to persist on the filestore blob. Surfaced back in the attachment chip and download Content-Disposition; users see this exact string.

mime_type
required
string non-empty

MIME type of the file. Almost any MIME is accepted; the server enforces a denylist (comments.attachments.blocked-mime-types) of known XSS vectors and executable formats (SVG, raw HTML / JS, .exe, .msi, shell scripts, …). Inline rendering in the comment body still requires an image MIME or application/pdf; non-image attachments render as chips below the body and link out to download.

size_bytes
required
string <int64> >= 1

File size in bytes. Must be > 0 and ≤ comments.attachments.max-bytes-per-file (default 26 214 400 = 25 MiB). The presigned form caps the upload at exactly this size so the client cannot upload a larger file than declared.

Responses

Request samples

Content type
application/json

CreateFilterPhotoUpload

{
  • "original_file_name": "rtu-17-filter.jpg",
  • "mime_type": "image/jpeg",
  • "size_bytes": "248320"
}

Response samples

Content type
application/json

FilterPhotoUploadIntent

{}

Get a single comment by id

Returns one comment with its author and caller-scoped is_unread state. Used by the SSE-driven real-time wiring (the create event triggers a thin refetch to resolve the new author) and by deep-link openers that may target a comment which isn't on the currently visible list page. Requires the comments read grant and read access to the target object — the same gating as GET /api/v2/comments.

Authorizations:
BearerAuth
path Parameters
comment_id
required
string <uuid>
Example: 11111111-aaaa-bbbb-cccc-dddddddddddd

Id of the comment.

Responses

Response samples

Content type
application/json

EquipmentMaintenanceComment

{
  • "id": "00000000-0000-4000-8000-000000007501",
  • "target_type": "co:equipment",
  • "target_id": "6f3d2a10-0000-4000-8000-000000000101",
  • "root_comment_id": "00000000-0000-4000-8000-000000007501",
  • "body_markdown": "Replacement filter ordered.",
  • "author": {
    },
  • "created_at": "2026-03-03T10:45:00Z",
  • "updated_at": "2026-03-03T10:45:00Z",
  • "lock_version": 0,
  • "is_edited": false,
  • "is_moderated": false,
  • "is_deleted": false,
  • "is_deleted_by_moderator": false,
  • "is_unread": false,
  • "reactions": [ ],
  • "mentions": [ ],
  • "attachments": [ ]
}

Soft-delete a comment

Marks the comment as deleted. Author can delete own; users with the comments:delete grant can delete any. Idempotent: if the comment is already soft-deleted, the call is a no-op success. Soft-deleted comments stay in the list as tombstones with is_deleted=true and an empty body_markdown — the frontend renders a tombstone placeholder.

Authorizations:
BearerAuth
path Parameters
comment_id
required
string <uuid>
Example: 11111111-aaaa-bbbb-cccc-dddddddddddd

Id of the comment to soft-delete.

Responses

Response samples

Content type
application/problem+json
{
  • "title": "Validation failed",
  • "status": 422,
  • "detail": "One or more fields failed validation",
  • "instance": "string",
  • "errors": [
    ],
  • "data": {
    }
}

Edit an existing comment

Updates a comment's body. Author can edit own; users with the comments:update grant can edit any. Moderator edits (caller != author) require a non-blank edit_reason — the server returns 422 (comments.moderation-reason-required) when missing. On success an audit row is appended to so_comment_edits in the same transaction; the response carries the updated comment with is_edited (and, for moderator edits, is_moderated) set to true.

Concurrency model: optional optimistic locking. Include the lock_version you last read to guard the edit — if it no longer matches the stored version the API returns 409 Conflict (resource-conflict); omit it (or send null) for last-write-wins, where the request that commits second overwrites the first. Either way every edit is appended to so_comment_edits as a separate audit row, so clients that need to reconcile can consult GET /api/v2/comments/{comment_id}/edits after their write.

Authorizations:
BearerAuth
path Parameters
comment_id
required
string <uuid>
Example: 11111111-aaaa-bbbb-cccc-dddddddddddd

Id of the comment to edit.

Request Body schema: application/merge-patch+json
required
lock_version
integer or null <int64>

Optimistic-locking version: validated when provided (409 on mismatch); omitting it skips the concurrency check

body_markdown
string

New comment body in markdown. Omit to leave unchanged. Explicit null is rejected. Same allow-list as create: bold, italic, strikethrough (GFM ~~text~~), inline code, headings level 1–3, fenced code blocks, lists, blockquotes, http(s) links. Server enforces the 10_000-character cap and the markdown allow-list.

edit_reason
string or null

Reason for the edit. Required (non-blank) when the caller is moderating another user's comment under the comments:update grant. Stored on the audit row and surfaced to other moderators via the edit-history endpoint. Ignored for author edits. This is a per-edit annotation: omitting it (or sending null) leaves the edit without a reason rather than carrying over a previous one.

attachment_ids
Array of strings or null <uuid> [ items <uuid > ]

Replacement attachment list. Omit this field to leave the comment's attachments untouched — this is the typical case when the caller only wants to edit body_markdown. Explicit null is rejected. Sending an empty array [] explicitly clears every attachment and marks the dropped blobs deleted in filestore. Sending a populated array replaces the set: rows kept across the edit retain their internal id; rows absent from the array are removed and their blobs marked deleted; new ids are linked. Inline references in body_markdown via ![alt](attachment:<uuid>) must also appear in this array. Capped at comments.attachments.max-per-comment (default 10) — exceeding the cap returns comments/too-many-attachments (422).

Responses

Request samples

Content type
application/merge-patch+json
Example

UpdateFilterComment

{
  • "body_markdown": "Replacement filter ordered for Friday.",
  • "lock_version": 0
}

Response samples

Content type
application/json

UpdatedFilterComment

{
  • "id": "00000000-0000-4000-8000-000000007501",
  • "target_type": "co:equipment",
  • "target_id": "6f3d2a10-0000-4000-8000-000000000101",
  • "root_comment_id": "00000000-0000-4000-8000-000000007501",
  • "body_markdown": "Replacement filter ordered for Friday.",
  • "author": {
    },
  • "created_at": "2026-03-03T10:45:00Z",
  • "updated_at": "2026-03-03T11:00:00Z",
  • "lock_version": 1,
  • "last_edited_at": "2026-03-03T11:00:00Z",
  • "is_edited": true,
  • "is_moderated": false,
  • "is_deleted": false,
  • "is_deleted_by_moderator": false,
  • "is_unread": false,
  • "reactions": [ ],
  • "mentions": [ ],
  • "attachments": [ ]
}

Get the page index containing a comment in the list response

Computes which page of GET /api/v2/comments contains [id] under the given sort + size. Used by deep-link openers (frontend ?commentId=…) to jump straight to the right page without paginating one click at a time. In threaded mode the returned page is the page of root comments; if the target is a reply, its row appears under its root on that page. Requires the comments read grant and read access to the target object — the same gating as the list endpoint.

Authorizations:
BearerAuth
path Parameters
comment_id
required
string <uuid>
Example: 11111111-aaaa-bbbb-cccc-dddddddddddd

Id of the comment to locate.

query Parameters
sort
string
Default: "threaded:desc"
Enum: "threaded:desc" "threaded:asc" "flat:desc" "flat:asc"
Example: sort=threaded:desc

Same <mode>:<direction> value as GET /api/v2/comments?sort=…. Default threaded:desc.

size
integer [ 1 .. 1000 ]
Default: 20
Example: size=20

Page size used for the index calculation. Must match the size the client uses when fetching the list, or the page index will be wrong. Range 1..1000.

Responses

Response samples

Content type
application/json

EquipmentCommentPageInfo

{
  • "comment_id": "00000000-0000-4000-8000-000000007501",
  • "root_comment_id": "00000000-0000-4000-8000-000000007501",
  • "mode": "threaded",
  • "page": 0,
  • "total_pages": 1
}

Get a comment's edit history (moderator only)

Returns the ordered audit trail for a single comment, newest-first. Each entry includes the editor reference, the body as it stood before the edit, the (moderator) edit_reason, the per-edit attachment-name diff (attachments_added_names / attachments_removed_names), and is_moderation (derived from editor.id != author.id). Requires the comments:update grant.

Authorizations:
BearerAuth
path Parameters
comment_id
required
string <uuid>
Example: 11111111-aaaa-bbbb-cccc-dddddddddddd

Id of the comment.

Responses

Response samples

Content type
application/json

FilterCommentEditHistory

{
  • "items": [
    ]
}

Get the richer detail view for a mention target

Returns email + roles (and equivalent richer fields for future types) so the read-path mention popover can render without a second round-trip. Auth only — every logged-in user can resolve mention details on comments they can read.

Deleted targets return 200 with is_deleted=true and best-effort cached data (display name, roles, email-at-time-of-deletion). This deviates from strict REST semantics — a 404 / 410 would lose the cached fields the popover renders as 'deleted user — last known: '. Clients must check is_deleted before treating the response as a live target. Unknown ids (e.g. cross-tenant) return 404 comments/mention-target-not-found.

Authorizations:
BearerAuth
path Parameters
target_type
required
string
Value: "user"
Example: user

Mention-type discriminator.

target_id
required
string <uuid>
Example: 11111111-aaaa-bbbb-cccc-dddddddddddd

Target id.

Responses

Response samples

Content type
application/json

AlpineUserMentionDetail

{
  • "type": "user",
  • "id": "00000000-0000-4000-8000-000000000102",
  • "display_name": "Jonas Leitner",
  • "is_deleted": false,
  • "email": "jonas.leitner@example.invalid",
  • "roles": [
    ]
}

List mention suggestions for the picker

Returns up to limit mention targets matching search for the requested target_type. Ranked: prefix-matches first (alpha-sorted within), substring matches second (alpha-sorted within). Empty search returns the top-N targets alpha-sorted. Requires the comments:create grant — read-only viewers never need the picker. Tenant scope is enforced by the schema interceptor.

Authorizations:
BearerAuth
query Parameters
search
string
Example: search=ali

Free-text query. Matches against first / last name and email for user mentions. Empty / missing → top-N alpha-sorted.

target_type
string
Example: target_type=user

Mention-type discriminator to search. Currently only user; future variants slot in here.

limit
integer [ 1 .. 50 ]
Default: 10
Example: limit=10

Maximum number of suggestions to return. Range 1..50.

Responses

Response samples

Content type
application/json

AlpineUserMentionSuggestions

{
  • "items": [
    ]
}

Get comment counts for target ids

Returns total and caller-scoped unread counts for every requested target the caller may read, preserving request order. Readable targets with no comments receive explicit zero counts. Missing and unreadable targets are omitted without revealing whether they exist. Tombstones are excluded from both counts.

Authorizations:
BearerAuth
query Parameters
target_type
required
string
Example: target_type=bw:case

Family-prefixed identifier of the object the comments are attached to. Examples: "co:<slug>" for custom-object instances, "bw:case" for BW cases.

target_ids
required
Array of strings <uuid> [ 1 .. 100 ] items [ items <uuid > ]
Example: target_ids=22222222-2222-3333-4444-555555555555

Target ids to count for. Supply 1 to 100 UUIDs by repeating the plural target_ids parameter.

Responses

Response samples

Content type
application/json

EquipmentCommentCounts

{
  • "items": [
    ]
}

Re-issue presigned URLs for an existing comment attachment

Presigned URLs returned on the comment list endpoint expire after comments.attachments.download-url-ttl-seconds (default 5 min). This endpoint refreshes them for a single attachment — used by the preview modal when the user opens a chip / inline image long after the comment was first rendered.

Authorisation gate: the caller must be authenticated in the tenant and the parent comment must exist and be live (not soft-deleted) — Phase 5 will additionally enforce target-object read access.

Error contract:

  • 404 comments/attachment-not-found when no attachment row matches the id, when its parent comment was hard-deleted (FK cascade drops the row), or when the parent comment has been soft-deleted.
  • 410 comments/attachment-blob-gone when the row exists but the underlying filestore blob has been hard-deleted (target cascade, manual purge, orphan-cleanup gap). The client should NOT retry; the list endpoint still surfaces the row with is_deleted=true so the comment body keeps its placeholder chip.
Authorizations:
BearerAuth
path Parameters
attachment_id
required
string <uuid>
Example: 11111111-aaaa-bbbb-cccc-dddddddddddd

Comment attachment id.

Responses

Response samples

Content type
application/json

FilterPhotoDownloadUrls

Remove the caller's reaction from a comment

Removes the calling user's reaction row addressed by the opaque {reaction_id} (read from reactions[*].your_reaction_id on a recent CommentResponse). Returns the updated comment. 404 comments/reaction-not-found when the id does not exist OR belongs to a different user — both cases return the same problem so the surface doesn't leak the existence of other users' reaction rows. The path id (rather than the emoji) avoids the fragile URL-encoding of skin-tone modifiers, ZWJ sequences, and similar. Removal uses the stored value without reparsing it so historical or manually repaired rows remain cleanable.

Authorizations:
BearerAuth
path Parameters
comment_id
required
string <uuid>
Example: 11111111-aaaa-bbbb-cccc-dddddddddddd

Id of the comment to un-react from. Used only for routing — the reaction id alone is sufficient to identify the row to remove.

reaction_id
required
string <uuid>
Example: 33333333-aaaa-bbbb-cccc-dddddddddddd

Opaque id of the caller's reaction row. Read from reactions[*].your_reaction_id on a recent comment response (set when you_reacted == true).

Responses

Response samples

Content type
application/json

CommentWithoutReaction

{
  • "id": "00000000-0000-4000-8000-000000007501",
  • "target_type": "co:equipment",
  • "target_id": "6f3d2a10-0000-4000-8000-000000000101",
  • "root_comment_id": "00000000-0000-4000-8000-000000007501",
  • "body_markdown": "Replacement filter ordered.",
  • "author": {
    },
  • "created_at": "2026-03-03T10:45:00Z",
  • "updated_at": "2026-03-03T10:45:00Z",
  • "lock_version": 0,
  • "is_edited": false,
  • "is_moderated": false,
  • "is_deleted": false,
  • "is_deleted_by_moderator": false,
  • "is_unread": false,
  • "reactions": [ ],
  • "mentions": [ ],
  • "attachments": [ ]
}

Delete an uploaded-but-not-yet-linked comment attachment

Marks the filestore blob as deleted so storage is reclaimed immediately when the user changes their mind about an attachment in the composer (clicks the pill ✕ before posting the comment). Without this endpoint, abandoned uploads sit on filestore for up to comments.attachments.orphan-retention-hours (default 24) before the nightly orphan-cleanup task sweeps them.

Idempotent. Repeated DELETEs return 204; the second call is a no-op on an already-deleted file.

Scope. Only deletes files whose source_key is COMMENT_ATTACHMENTS AND that are NOT yet linked to a posted comment. Once a file is part of so_comment_attachments the proper removal path is the comment-delete endpoint (which cascades blob removal via the comment hard-delete hook).

Authorisation gate. Requires the comments:create grant — same as the upload-intent endpoint. There is no per-uploader check: filestore does not track uploader identity and UUID-unguessability + schema-per-tenant isolation are the gates against cross-user / cross-tenant abuse, matching the orphan-cleanup task's posture (which also treats every unreferenced file the same way regardless of who uploaded it).

Not exposed via MCP — abandoned-upload cleanup is a UI-driven affordance and the agent surface doesn't have a use case for it.

Authorizations:
BearerAuth
path Parameters
attachment_id
required
string <uuid>
Example: 11111111-aaaa-bbbb-cccc-dddddddddddd

Comment attachment id of the abandoned upload.

Responses

Response samples

Content type
application/problem+json
{
  • "title": "Validation failed",
  • "status": 422,
  • "detail": "One or more fields failed validation",
  • "instance": "string",
  • "errors": [
    ],
  • "data": {
    }
}

Sms Gateways

Manage SMS gateway configurations per tenant. Gateways are evaluated by priority (0 = primary) for failover.

List all SMS gateways for the current tenant

Returns gateways ordered by priority (0 = primary). Disabled gateways are included.

Authorizations:
BearerAuth

Responses

Response samples

Content type
application/json

GatewaysList

{
  • "items": [
    ]
}

Create a new SMS gateway

Creates a tenant SMS gateway and returns its effective priority and configuration.

Authorizations:
BearerAuth
Request Body schema: application/json
required
name
required
string non-empty

Tenant-visible gateway name.

type
required
string
Enum: "TWILIO" "CUSTOM_HTTP"

Gateway integration type.

priority
integer <int32> >= 0

Requested zero-based failover position. Omit to append the gateway.

enabled
boolean
Default: true

Whether the gateway may be used immediately. Defaults to true.

object (TwilioGatewayConfig)

Required when type is TWILIO; omit for CUSTOM_HTTP.

object (CustomSmsSettings)

Required when type is CUSTOM_HTTP; omit for TWILIO.

Responses

Request samples

Content type
application/json

CreateAlpineTwilioGateway

{
  • "name": "Alpine primary SMS",
  • "type": "TWILIO",
  • "priority": 0,
  • "enabled": true,
  • "twilio_config": {
    }
}

Response samples

Content type
application/json

CreateTwilioGateway

{
  • "id": "11111111-2222-3333-4444-555555555555",
  • "name": "Primary Twilio",
  • "type": "TWILIO",
  • "priority": 0,
  • "enabled": true,
  • "lock_version": 0,
  • "twilio_config": {
    }
}

Send a test SMS using a gateway

Queues a test message through the selected gateway and returns its tracking id.

Authorizations:
BearerAuth
path Parameters
sms_gateway_id
required
string <uuid>

Gateway identifier

Request Body schema: application/json
required
phone_number
required
string non-empty

International recipient number with an explicit '+' country code. Formatted input is normalized to E.164.

Responses

Request samples

Content type
application/json

SendTechnicianTestSms

{
  • "phone_number": "+436641234567"
}

Response samples

Content type
application/json

TestSmsAccepted

{
  • "tracking_id": "00000000-0000-4000-8000-000000004901"
}

Reorder gateways atomically

Reorders all gateways for the current tenant; request must list every gateway exactly once in the desired order (0 = primary).

Authorizations:
BearerAuth
Request Body schema: application/json
required
gateway_ids
required
Array of strings <uuid> non-empty [ items <uuid > ]

Responses

Request samples

Content type
application/json

PrioritizeGateways

{
  • "gateway_ids": [
    ]
}

Response samples

Content type
application/problem+json
{
  • "title": "Validation failed",
  • "status": 422,
  • "detail": "One or more fields failed validation",
  • "instance": "string",
  • "errors": [
    ],
  • "data": {
    }
}

Get a single SMS gateway

Returns the full gateway configuration for the given ID.

Authorizations:
BearerAuth
path Parameters
sms_gateway_id
required
string <uuid>

Gateway identifier

Responses

Response samples

Content type
application/json

GatewayResponse

{
  • "id": "11111111-2222-3333-4444-555555555555",
  • "name": "Primary Twilio",
  • "type": "TWILIO",
  • "priority": 0,
  • "enabled": true,
  • "lock_version": 0,
  • "twilio_config": {
    }
}

Delete an SMS gateway

Permanently removes the tenant SMS gateway.

Authorizations:
BearerAuth
path Parameters
sms_gateway_id
required
string <uuid>

Gateway identifier

Responses

Response samples

Content type
application/problem+json
{
  • "title": "Validation failed",
  • "status": 422,
  • "detail": "One or more fields failed validation",
  • "instance": "string",
  • "errors": [
    ],
  • "data": {
    }
}

Update an SMS gateway

Allows partial updates (name, enabled flag, priority).

Authorizations:
BearerAuth
path Parameters
sms_gateway_id
required
string <uuid>

Gateway identifier

Request Body schema: application/merge-patch+json
required
lock_version
integer or null <int64>

Optimistic-locking version: validated when provided (409 on mismatch); omitting it skips the concurrency check

name
string

Display name of the gateway. Omitted leaves the value unchanged; explicit null is rejected (422) — it cannot be cleared.

enabled
boolean

Whether the gateway is enabled. Omitted leaves the value unchanged; explicit null is rejected (422) — it cannot be cleared.

priority
integer <int32>

Evaluation priority (0 = primary). Omitted leaves the value unchanged; explicit null is rejected (422) — it cannot be cleared.

object (TwilioGatewayConfig)

Replaces the whole Twilio configuration when provided (gateway must be of type TWILIO). Omitted leaves the configuration unchanged; explicit null is rejected (422).

object (CustomSmsSettings)

Replaces the whole custom-HTTP configuration when provided (gateway must be of type CUSTOM_HTTP). Omitted leaves the configuration unchanged; explicit null is rejected (422).

Responses

Request samples

Content type
application/merge-patch+json

DisableGateway

{
  • "lock_version": 0,
  • "enabled": false
}

Response samples

Content type
application/json

UpdateGateway

{
  • "id": "11111111-2222-3333-4444-555555555555",
  • "name": "Renamed Gateway",
  • "type": "TWILIO",
  • "priority": 0,
  • "enabled": false,
  • "lock_version": 1,
  • "twilio_config": {
    }
}

Webhook Delivery Failures

View recorded webhook failures and retry status

List webhook delivery failures

Retrieve a paginated list of webhook delivery failures for the current tenant.

A row represents the latest recorded failed attempt for one webhook message. The same row is updated when another retry fails, while the first and latest failure timestamps remain available. This endpoint is not a full delivery or per-attempt audit ledger: successful attempts and deliveries skipped before an HTTP request are not recorded. A successful retry after an earlier failure does not add a success record, so absence does not prove success and presence alone does not prove the message ultimately failed.

Use the filters to narrow down results by time range, endpoint, or event type.

Requires any of 'webhooks:read', 'webhooks:create', or 'webhooks:update' grant.

Authorizations:
BearerAuth
query Parameters
page
integer >= 0
Default: 0

Page number (0-based). First page is 0.

size
integer [ 1 .. 100 ]
Default: 20
Example: size=20

Number of items per page. Maximum allowed is 100.

failed_from
string <date-time>
Example: failed_from=2024-01-01T00:00:00Z

Return failures whose first failed attempt occurred at or after this RFC 3339 timestamp (inclusive).

failed_to
string <date-time>
Example: failed_to=2025-01-01T00:00:00Z

Return failures whose first failed attempt occurred before this RFC 3339 timestamp (exclusive).

endpoint_id
string <uuid>
Example: endpoint_id=019bb29d-2458-722e-b21b-679e632ca96b

Filter by specific webhook endpoint ID.

event_type
string
Example: event_type=area.created

Filter by event type.

sort
string
Default: "first_attempt_failed_at:desc"
Example: sort=first_attempt_failed_at:desc

Single sorting criterion in property:direction format. Allowed properties: first_attempt_failed_at, attempt, event_type, endpoint_id. Allowed directions: asc, desc. Default is first_attempt_failed_at:desc.

Responses

Response samples

Content type
application/json

DeliveryFailuresResponse

{
  • "items": [
    ],
  • "page": {
    }
}

Custom Object Definitions

API for managing custom object definitions

Get a custom object definition

Retrieves a custom object definition by slug

Authorizations:
BearerAuth
path Parameters
definition_slug
required
string

Slug of the custom-object definition.

Responses

Response samples

Content type
application/json

EquipmentDefinition

{
  • "id": "6f3d2a10-0000-4000-8000-000000000001",
  • "schema": {
    },
  • "created_at": "2026-03-01T08:00:00Z",
  • "updated_at": "2026-03-03T10:20:00Z",
  • "lock_version": 5,
  • "effective_access_level": "manage"
}

Update a custom object definition

Updates an existing custom object definition.

Authorizations:
BearerAuth
path Parameters
definition_slug
required
string

Slug of the custom-object definition.

Request Body schema: application/json
required
lock_version
integer <int64>

Optimistic-locking version: validated when provided (409 on mismatch); omitting it skips the concurrency check

required
object (CustomObjectSchemaInput)

Updated JSON Schema definition

Responses

Request samples

Content type
application/json

ReplaceEquipmentDefinition

{
  • "lock_version": 3,
  • "schema": {
    }
}

Response samples

Content type
application/json

ReplacedEquipmentDefinition

{
  • "id": "6f3d2a10-0000-4000-8000-000000000001",
  • "schema": {
    },
  • "created_at": "2026-03-01T08:00:00Z",
  • "updated_at": "2026-03-03T10:15:00Z",
  • "lock_version": 4,
  • "effective_access_level": "manage"
}

Delete a custom object definition

Deletes a custom object definition including its database table.

Authorizations:
BearerAuth
path Parameters
definition_slug
required
string

Slug of the custom-object definition.

Responses

Response samples

Content type
application/problem+json
{
  • "title": "Validation failed",
  • "status": 422,
  • "detail": "One or more fields failed validation",
  • "instance": "string",
  • "errors": [
    ],
  • "data": {
    }
}

Update a definition's display template

Updates only the display template of a custom object definition. The display template is a presentation-only field, so this is permitted for built-in and read-only system definitions whose schema structure cannot otherwise be modified.

Authorizations:
BearerAuth
path Parameters
definition_slug
required
string

Slug of the custom-object definition.

Request Body schema: application/json
required
lock_version
integer <int64>

Optimistic-locking version: validated when provided (409 on mismatch); omitting it skips the concurrency check

display_template
string

Display template: free text interleaved with {{attribute_slug}} placeholders (e.g. {{firstname}} {{lastname}}). Send null or an empty string to clear it.

Responses

Request samples

Content type
application/json

SetEquipmentDisplayTemplate

{
  • "lock_version": 4,
  • "display_template": "{{name}} · {{asset_tag}}"
}

Response samples

Content type
application/json

EquipmentDisplayTemplateUpdated

{
  • "id": "6f3d2a10-0000-4000-8000-000000000001",
  • "schema": {
    },
  • "created_at": "2026-03-01T08:00:00Z",
  • "updated_at": "2026-03-03T10:20:00Z",
  • "lock_version": 5,
  • "effective_access_level": "manage"
}

List all custom object definitions

Retrieves all custom object definitions

Authorizations:
BearerAuth
query Parameters
page
integer >= 0
Default: 0

Page number (0-based).

size
integer [ 1 .. 100 ]
Default: 20
Example: size=20

Number of items per page (max 100).

read_only
boolean

Filter definitions by their read-only flag. Pass true to list only system (read-only) definitions, false to list only custom (editable) definitions. Omit the parameter to list both.

built_in
boolean

Filter definitions by their built-in flag. Pass true to list only predefined (system-seeded) definitions, false to list only user-created definitions. Omit the parameter to list both. When both built_in and read_only are supplied, built_in takes precedence.

Responses

Response samples

Content type
application/json

EquipmentDefinitionsPage

{
  • "items": [
    ],
  • "page": {
    }
}

Create a custom object definition

Creates a new custom object definition.

Authorizations:
BearerAuth
Request Body schema: application/json
required
required
object (CustomObjectSchemaInput)

JSON Schema definition

Array of objects (RelationSchema)

Relations to create along with this definition

Responses

Request samples

Content type
application/json

CreateEquipmentDefinition

{
  • "schema": {
    }
}

Response samples

Content type
application/json

CreatedEquipmentDefinition

{
  • "id": "6f3d2a10-0000-4000-8000-000000000001",
  • "schema": {
    },
  • "created_at": "2026-03-01T08:00:00Z",
  • "updated_at": "2026-03-01T08:00:00Z",
  • "lock_version": 0,
  • "effective_access_level": "manage"
}

Measure Units

Tenant capacity measure-unit registry (kg, m³, litres, …)

List measure units

Returns measure units ordered by name, paginated.

Authorizations:
BearerAuth
query Parameters
page
integer >= 0
Default: 0

Page number (0-based).

size
integer [ 1 .. 100 ]
Default: 20
Example: size=20

Number of items per page (max 100).

Responses

Response samples

Content type
application/json

CapacityUnitsPage

{
  • "items": [
    ],
  • "page": {
    }
}

Create a measure unit

Creates a tenant measure unit with a unique name and symbol.

Authorizations:
BearerAuth
Request Body schema: application/json
required
name
required
string non-empty

Human-readable name, e.g. "Kilogram"

symbol
required
string non-empty

Symbol, e.g. "kg"

Responses

Request samples

Content type
application/json

CreateKilogramsUnit

{
  • "name": "Kilograms",
  • "symbol": "kg"
}

Response samples

Content type
application/json

CreatedKilogramsUnit

{
  • "id": "00000000-0000-4000-8000-000000006501",
  • "name": "Kilograms",
  • "symbol": "kg",
  • "created_at": "2026-08-20T08:20:00Z",
  • "updated_at": "2026-08-20T08:20:00Z",
  • "lock_version": 0
}

Get a measure unit by id

Returns one tenant measure unit by its UUID.

Authorizations:
BearerAuth
path Parameters
measure_unit_id
required
string <uuid>

UUID of the measure unit.

Responses

Response samples

Content type
application/json

KilogramsUnit

{
  • "id": "00000000-0000-4000-8000-000000006501",
  • "name": "Kilograms",
  • "symbol": "kg",
  • "created_at": "2026-08-20T08:20:00Z",
  • "updated_at": "2026-08-20T08:20:00Z",
  • "lock_version": 0
}

Delete a measure unit

Permanently removes a tenant measure unit.

Authorizations:
BearerAuth
path Parameters
measure_unit_id
required
string <uuid>

UUID of the measure unit.

Responses

Response samples

Content type
application/problem+json
{
  • "title": "Validation failed",
  • "status": 422,
  • "detail": "One or more fields failed validation",
  • "instance": "string",
  • "errors": [
    ],
  • "data": {
    }
}

Update a measure unit

Partial update: omitted fields remain unchanged.

Authorizations:
BearerAuth
path Parameters
measure_unit_id
required
string <uuid>

UUID of the measure unit.

Request Body schema: application/merge-patch+json
required
name
string

Human-readable name, e.g. "Kilogram". Omitted leaves the value unchanged. Explicit null is rejected (422) — name is required and cannot be cleared.

symbol
string

Symbol, e.g. "kg". Omitted leaves the value unchanged. Explicit null is rejected (422) — symbol is required and cannot be cleared.

lock_version
integer or null <int64>

Lock version for optimistic locking

Responses

Request samples

Content type
application/merge-patch+json

UpdateKilogramsName

{
  • "name": "Kilograms (kg)",
  • "lock_version": 0
}

Response samples

Content type
application/json

UpdatedKilogramsUnit

{
  • "id": "00000000-0000-4000-8000-000000006501",
  • "name": "Kilograms (kg)",
  • "symbol": "kg",
  • "created_at": "2026-08-20T08:20:00Z",
  • "updated_at": "2026-08-20T09:20:00Z",
  • "lock_version": 1
}

Billing Portal

Stripe Billing Portal and payment-method API

Re-check billing status against Stripe

Pulls the tenant's live subscription status from Stripe and updates the stored billing standing, then returns the refreshed decision. Acts as a fallback when a Stripe webhook has not yet arrived — e.g. a user who just updated their payment method on the billing-locked screen and wants to unlock immediately. Reachable while the tenant is billing-locked.

Authorizations:
BearerAuth

Responses

Response samples

Content type
application/json

ActiveAlpineBilling

{
  • "allowed": true,
  • "status": "ACTIVE"
}

Open a Stripe Customer Portal session

Returns a one-time URL the client should redirect the user to so they can manage their payment method in Stripe's hosted Customer Portal. The tenant must already have a Stripe customer (paid plan).

Authorizations:
BearerAuth
Request Body schema: application/json
required
return_url
required
string [ 0 .. 2048 ] characters

Absolute URL the customer is redirected to after closing the Stripe Customer Portal. The origin must match the tenant's primary domain or one of its configured custom domains.

Responses

Request samples

Content type
application/json

CreateAlpineBillingPortalSession

Response samples

Content type
application/json

AlpineBillingPortalSession

Get the default payment method on file

Returns a summary (brand, last4, expiry) of the default payment method attached to the tenant's Stripe customer. The has_payment_method flag is false when no card is on file yet.

Authorizations:
BearerAuth

Responses

Response samples

Content type
application/json

AlpinePaymentMethod

{
  • "has_payment_method": true,
  • "brand": "visa",
  • "last4": "4242",
  • "exp_month": 12,
  • "exp_year": 2028
}

Tenant

Tenant API

Create a tenant logo upload intent

Creates a presigned upload form for a new tenant logo.

Authorizations:
BearerAuth
Request Body schema: application/json
required
original_file_name
required
string non-empty

Original filename

mime_type
required
string non-empty

MIME type

Responses

Request samples

Content type
application/json

CreateTenantLogoUpload

{
  • "original_file_name": "alpine-facility-services-logo.svg",
  • "mime_type": "image/svg+xml"
}

Response samples

Content type
application/json

AlpineTenantLogoUpload

{}

Create a tenant favicon upload intent

Creates a presigned upload form for a new tenant favicon.

Authorizations:
BearerAuth
Request Body schema: application/json
required
original_file_name
required
string non-empty

Original filename

mime_type
required
string non-empty

MIME type

Responses

Request samples

Content type
application/json

CreateTenantFaviconUpload

{
  • "original_file_name": "alpine-favicon.png",
  • "mime_type": "image/png"
}

Response samples

Content type
application/json

AlpineTenantFaviconUpload

{}

Get tenant

Returns the tenant data for the authenticated account.

Authorizations:
BearerAuth

Responses

Response samples

Content type
application/json

AlpineTenant

{
  • "name": "Alpine Facility Services GmbH",
  • "language": "de",
  • "region": "AT",
  • "timezone": "Europe/Vienna",
  • "lock_version": 0
}

Update tenant

JSON Merge Patch (RFC 7386). Omitted fields remain unchanged.

Authorizations:
BearerAuth
Request Body schema: application/merge-patch+json
required
name
string <= 255 characters

Tenant name. Omitted leaves the value unchanged; explicit null is rejected (422).

language
string <= 10 characters

Tenant content language tag. Legacy locale-style values such as en-US are accepted and normalized. Omitted leaves the value unchanged; explicit null is rejected (422).

region
string <= 2 characters

Tenant region as ISO 3166-1 alpha-2 country code. Omitted leaves the value unchanged; explicit null is rejected (422).

timezone
string <= 50 characters

Tenant timezone as IANA timezone identifier. Omitted leaves the value unchanged; explicit null is rejected (422).

lock_version
integer or null <int64>

Optimistic-locking version: validated when provided (409 on mismatch); omitting it skips the concurrency check.

Responses

Request samples

Content type
application/merge-patch+json
Example

UpdateName

{
  • "name": "Alpine Facility Services GmbH",
  • "lock_version": 0
}

Response samples

Content type
application/json

UpdatedAlpineTenant

{
  • "name": "Alpine Facility Services GmbH",
  • "language": "de",
  • "region": "AT",
  • "timezone": "Europe/Vienna",
  • "lock_version": 0
}

Get tenant logo upload status

Returns upload and application status for a tenant logo upload intent.

Authorizations:
BearerAuth
path Parameters
file_id
required
string <uuid>

UUID of the uploaded file.

Responses

Response samples

Content type
application/json

UploadedAlpineTenantLogo

{}

Get the tenant favicon

Returns the current tenant favicon URL when a favicon is configured.

Authorizations:
BearerAuth

Responses

Response samples

Content type
application/json

AlpineTenantFavicon

Delete the tenant favicon

Removes the current tenant favicon. Repeating the request is safe.

Authorizations:
BearerAuth

Responses

Response samples

Content type
application/problem+json
{
  • "title": "Validation failed",
  • "status": 422,
  • "detail": "One or more fields failed validation",
  • "instance": "string",
  • "errors": [
    ],
  • "data": {
    }
}

Get tenant favicon upload status

Returns upload and application status for a tenant favicon upload intent.

Authorizations:
BearerAuth
path Parameters
file_id
required
string <uuid>

UUID of the uploaded file.

Responses

Response samples

Content type
application/json

UploadedAlpineTenantFavicon

{}

AI Assistant Settings

Manage AI assistant settings for the tenant.

Get AI assistant settings

Returns the current AI assistant operating mode for this tenant.

Authorizations:
BearerAuth

Responses

Response samples

Content type
application/json

ReadOnlyAssistantSettings

{
  • "mode": "READ_ONLY",
  • "enabled": true,
  • "tool_mode": "READ_ONLY",
  • "tenant_id": "00000000-0000-4000-8000-000000000001"
}

Update AI assistant settings

Updates the AI assistant mode. OFF disables the assistant, READ_ONLY enables read-only tools, and READ_WRITE enables read and write-capable tools.

Authorizations:
BearerAuth
Request Body schema: application/merge-patch+json
required
mode
string
Enum: "OFF" "READ_ONLY" "READ_WRITE"

New assistant mode. OFF disables the assistant, READ_ONLY enables read-only tool access, READ_WRITE enables read and write-capable tool access. Omit to leave unchanged; explicit null is rejected (422).

Responses

Request samples

Content type
application/merge-patch+json

EnableReadOnlyAssistant

{
  • "mode": "READ_ONLY"
}

Response samples

Content type
application/json

UpdatedReadOnlyAssistantSettings

{
  • "mode": "READ_ONLY",
  • "enabled": true,
  • "tool_mode": "READ_ONLY",
  • "tenant_id": "00000000-0000-4000-8000-000000000001"
}

Grants

Grant listing API.

List grants

Returns the list of grants available for roles.

Authorizations:
BearerAuth

Responses

Response samples

Content type
application/json

GrantListResponse

{
  • "items": [
    ]
}

Devices

Device management API

List devices

Returns a paginated list of devices with their latest telemetry snapshot.

Authorizations:
BearerAuth
query Parameters
page
integer >= 0
Default: 0

Page number (0-based).

size
integer [ 1 .. 100 ]
Default: 20

Number of items per page (max 100).

sort
Array of strings
Example: sort=natural_id:asc

Repeated sorting criteria in field:direction format. Allowed fields: id, natural_id, created_at, updated_at, device_model, device_identity_id, kind, provisioning_state, last_received_at, last_reported_at. Default: created_at:desc.

search
string

Search term for model, identity, phone number, or description.

model
string

Filter by device model (case-insensitive substring match).

kind
string
Enum: "TOURFOLD_APP" "THIRD_PARTY_OSMAND" "TRACKING_DEVICE"

Filter by device kind.

has_location
boolean

Filter to devices with or without a latest location.

updated_from
string <date-time>

Filter to devices updated at or after this timestamp.

updated_to
string <date-time>

Filter to devices updated before this timestamp.

include
Array of strings
Items Value: "current_state"
Example: include=current_state

Optional related resources to embed. Supported: current_state.

min_lat
number <double> [ -90 .. 90 ]

Latest-location bounding box: minimum latitude. All four bbox corners must be supplied together.

min_lon
number <double> [ -180 .. 180 ]

Latest-location bounding box: minimum longitude. All four bbox corners must be supplied together.

max_lat
number <double> [ -90 .. 90 ]

Latest-location bounding box: maximum latitude. All four bbox corners must be supplied together.

max_lon
number <double> [ -180 .. 180 ]

Latest-location bounding box: maximum longitude. All four bbox corners must be supplied together.

Responses

Response samples

Content type
application/json

TechnicianDevicesPage

{
  • "items": [
    ],
  • "page": {
    }
}

Create a device

Creates a device. Provisioning state is system-managed and is not accepted in this request.

Authorizations:
BearerAuth
Request Body schema: application/json
required
kind
string
Enum: "TOURFOLD_APP" "THIRD_PARTY_OSMAND" "TRACKING_DEVICE"

Device kind. Defaults to TOURFOLD_APP when omitted.

device_model
string [ 0 .. 128 ] characters

Human-readable model or tracker type

device_identity_id
string [ 0 .. 255 ] characters

Stable device identifier such as a generated app installation id, OsmAnd id, or tracker protocol id

connection_profile
string [ 0 .. 128 ] characters

Provider connection profile selected for tracking hardware, for example OSMAND_HTTP_ONLY

phone_number
string [ 0 .. 32 ] characters

International phone number. An explicit '+' country code is required; common formatting is accepted and normalized to canonical E.164. National numbers are rejected.

platform
string
Enum: "UNKNOWN" "IOS" "ANDROID"

Mobile platform when known

description
string [ 0 .. 2048 ] characters

Optional operator notes

Responses

Request samples

Content type
application/json

CreateTechnicianDevice

{
  • "kind": "TOURFOLD_APP",
  • "device_model": "Pixel 9",
  • "device_identity_id": "jonas-pixel-9",
  • "phone_number": "+43 664 123 45 67",
  • "platform": "ANDROID",
  • "description": "Jonas Leitner's service device"
}

Response samples

Content type
application/json

CreatedTechnicianDevice

{
  • "id": "00000000-0000-4000-8000-000000004001",
  • "created_at": "2026-08-20T08:00:00Z",
  • "updated_at": "2026-08-20T08:00:00Z",
  • "lock_version": 0,
  • "natural_id": 17,
  • "kind": "TOURFOLD_APP",
  • "device_model": "Pixel 9",
  • "device_identity_id": "jonas-pixel-9",
  • "provisioning_state": "PROVISIONED",
  • "phone_number": "+436641234567",
  • "platform": "ANDROID",
  • "description": "Jonas Leitner's service device"
}

Generate a device setup code

Generates a setup payload the client renders as a QR code. The payload is routed by device kind: a rotating Tourfold App enrollment link, the idempotent OsmAnd intake URL, or the tracking-device connection-profile endpoint. Secret-bearing material is only ever returned from this action, never from Device reads.

Authorizations:
BearerAuth
path Parameters
device_id
required
string <uuid>

UUID of the device.

Responses

Response samples

Content type
application/json

TechnicianAppSetupCode

{}

Send a device setup SMS

Sends a Tourfold App setup link to the device's stored phone number. The link carries a one-time enrollment secret and is delivered only in the SMS — the response never includes the URL or secret. Supported for Tourfold App devices only.

Authorizations:
BearerAuth
path Parameters
device_id
required
string <uuid>

UUID of the device.

Responses

Response samples

Content type
application/json

TechnicianSetupSmsScheduled

{
  • "device_id": "00000000-0000-4000-8000-000000004001",
  • "sent_to": "+4369917246437",
  • "expires_at": "2026-08-20T10:30:00Z"
}

Rotate a device intake secret

Rotates the device intake secret, invalidating the previous one. Returns no body — the new usable configuration (URL + secret) is obtained via the setup-codes action, keeping a single rendering path and never exposing the secret in a cacheable response.

Authorizations:
BearerAuth
path Parameters
device_id
required
string <uuid>

UUID of the device.

Responses

Response samples

Content type
application/problem+json
{
  • "title": "Validation failed",
  • "status": 422,
  • "detail": "One or more fields failed validation",
  • "instance": "string",
  • "errors": [
    ],
  • "data": {
    }
}

Deactivate a device

Marks a device as inactive while keeping telemetry history and intake data.

Authorizations:
BearerAuth
path Parameters
device_id
required
string <uuid>

UUID of the device.

Responses

Response samples

Content type
application/json

DeactivatedTechnicianDevice

{
  • "id": "00000000-0000-4000-8000-000000004001",
  • "created_at": "2026-08-20T08:00:00Z",
  • "updated_at": "2026-08-20T10:00:00Z",
  • "lock_version": 2,
  • "natural_id": 17,
  • "kind": "TOURFOLD_APP",
  • "device_model": "Pixel 9",
  • "device_identity_id": "jonas-pixel-9",
  • "provisioning_state": "DISABLED",
  • "phone_number": "+4369917246437",
  • "platform": "ANDROID",
  • "description": "Jonas Leitner's service device"
}

Activate a device

Marks an inactive device as provisioned and usable again.

Authorizations:
BearerAuth
path Parameters
device_id
required
string <uuid>

UUID of the device.

Responses

Response samples

Content type
application/json

ActivatedTechnicianDevice

{
  • "id": "00000000-0000-4000-8000-000000004001",
  • "created_at": "2026-08-20T08:00:00Z",
  • "updated_at": "2026-08-20T08:00:00Z",
  • "lock_version": 0,
  • "natural_id": 17,
  • "kind": "TOURFOLD_APP",
  • "device_model": "Pixel 9",
  • "device_identity_id": "jonas-pixel-9",
  • "provisioning_state": "PROVISIONED",
  • "phone_number": "+436641234567",
  • "platform": "ANDROID",
  • "description": "Jonas Leitner's service device"
}

Get a device

Returns a device with its latest telemetry snapshot.

Authorizations:
BearerAuth
path Parameters
device_id
required
string <uuid>

UUID of the device.

query Parameters
include
Array of strings
Items Value: "current_state"
Example: include=current_state

Optional related resources to embed. Supported: current_state.

Responses

Response samples

Content type
application/json

TechnicianDevice

{
  • "id": "00000000-0000-4000-8000-000000004001",
  • "created_at": "2026-08-20T08:00:00Z",
  • "updated_at": "2026-08-20T08:00:00Z",
  • "lock_version": 0,
  • "natural_id": 17,
  • "kind": "TOURFOLD_APP",
  • "device_model": "Pixel 9",
  • "device_identity_id": "jonas-pixel-9",
  • "provisioning_state": "PROVISIONED",
  • "phone_number": "+436641234567",
  • "platform": "ANDROID",
  • "description": "Jonas Leitner's service device"
}

Delete a device

Deletes a device and its telemetry history.

Authorizations:
BearerAuth
path Parameters
device_id
required
string <uuid>

UUID of the device.

Responses

Response samples

Content type
application/problem+json
{
  • "title": "Validation failed",
  • "status": 422,
  • "detail": "One or more fields failed validation",
  • "instance": "string",
  • "errors": [
    ],
  • "data": {
    }
}

Update a device

JSON Merge Patch (RFC 7386): omitted fields remain unchanged; a field set to null is cleared (phone_number and description). Provisioning state is system-managed and cannot be changed through this endpoint.

Authorizations:
BearerAuth
path Parameters
device_id
required
string <uuid>

UUID of the device.

Request Body schema: application/merge-patch+json
required
lock_version
integer or null <int64>

Optimistic-locking version: validated when provided (409 on mismatch); omitting it skips the concurrency check

kind
string
Enum: "TOURFOLD_APP" "THIRD_PARTY_OSMAND" "TRACKING_DEVICE"

Device kind. Omitted leaves the value unchanged. Explicit null is rejected (422) — kind is required and cannot be cleared.

device_model
string or null

Human-readable model or tracker type. Omitted leaves the value unchanged; explicit null clears it.

device_identity_id
string or null

Stable device identifier. Omitted leaves the value unchanged; explicit null clears it. Once set it cannot be changed to a different value.

connection_profile
string or null

Provider connection profile selected for tracking hardware, for example OSMAND_HTTP_ONLY. Omitted leaves the value unchanged; explicit null clears it.

phone_number
string or null

International phone number. An explicit '+' country code is required; common formatting is accepted and normalized to canonical E.164. National numbers are rejected. Omitted leaves the value unchanged; explicit null clears it.

platform
string
Enum: "UNKNOWN" "IOS" "ANDROID"

Mobile platform. Omitted leaves the value unchanged. Explicit null is rejected (422) — platform is required and cannot be cleared.

description
string or null

Optional operator notes. Omitted leaves the value unchanged; explicit null clears it.

Responses

Request samples

Content type
application/merge-patch+json
Example

UpdateTechnicianPhone

{
  • "lock_version": 0,
  • "phone_number": "+43 699 172 464 37"
}

Response samples

Content type
application/json

UpdatedTechnicianDevice

{
  • "id": "00000000-0000-4000-8000-000000004001",
  • "created_at": "2026-08-20T08:00:00Z",
  • "updated_at": "2026-08-20T09:30:00Z",
  • "lock_version": 1,
  • "natural_id": 17,
  • "kind": "TOURFOLD_APP",
  • "device_model": "Pixel 9",
  • "device_identity_id": "jonas-pixel-9",
  • "provisioning_state": "PROVISIONED",
  • "phone_number": "+4369917246437",
  • "platform": "ANDROID",
  • "description": "Jonas Leitner's service device"
}

Get a device's current state

Returns the latest materialized state (status, location, battery, app) for one device.

Authorizations:
BearerAuth
path Parameters
device_id
required
string <uuid>

UUID of the device.

Responses

Response samples

Content type
application/json

TechnicianDeviceCurrentState

{
  • "device_id": "00000000-0000-4000-8000-000000004001",
  • "last_seen_at": "2026-08-20T09:29:45Z",
  • "status": {
    }
}

List supported device types

Returns neutral supported device kinds and setup profiles. Provider internals and credentials are not exposed.

Authorizations:
BearerAuth

Responses

Response samples

Content type
application/json

SupportedTrackingDevice

{
  • "items": [
    ]
}

Bulk-read device current states

Returns the latest materialized state for each requested, tenant-visible device id.

Authorizations:
BearerAuth
query Parameters
device_ids
Array of strings <uuid> [ items <uuid > ]

Device ids to retrieve (max 100). Repeat the device_ids query parameter for each value.

Responses

Response samples

Content type
application/json

TechnicianDeviceCurrentStates

{
  • "items": [
    ]
}

Custom Object Permissions

API for managing custom-object type permission matrices

Get a custom-object type's permission matrix

Returns the type's class-level access-control entries (per role/user/everyone). Requires the custom-objects:definitions:read grant plus, per type, the custom-objects:definitions:edit-permissions grant or ownership. Only PROTECTED types have a matrix (records / readOnly types return 422).

Authorizations:
BearerAuth
path Parameters
definition_slug
required
string

Slug of the custom-object definition.

Responses

Response samples

Content type
application/json

EquipmentPermissions

{
  • "definition_slug": "equipment",
  • "entries": [
    ]
}

Replace a custom-object type's permission matrix

Stores the supplied entries as the type's complete class-level matrix (a replace, not a merge). Requires the custom-objects:definitions:read grant plus, per type, the custom-objects:definitions:edit-permissions grant or ownership.

Authorizations:
BearerAuth
path Parameters
definition_slug
required
string

Slug of the custom-object definition.

Request Body schema: application/json
required
required
Array of objects (CustomObjectPermissionEntryInput)

The complete list of entries the type should have after this call.

Array
principal_type
required
string
Enum: "everyone" "role" "user"
role_name
string
user_id
string <uuid>
level
required
string
Enum: "read" "write"

Responses

Request samples

Content type
application/json
Example

ReplaceEquipmentPermissions

{
  • "entries": [
    ]
}

Response samples

Content type
application/json

ReplacedEquipmentPermissions

{
  • "definition_slug": "equipment",
  • "entries": [
    ]
}

Webhooks Catalog

Discover the event types you can subscribe to, and how deliveries are signed.

Webhook Delivery

When events occur in Tourfold, webhook payloads are sent via HTTP POST to your configured endpoint URLs. Each delivery carries these headers:

  • webhook-id: Unique message id (UUID). Stable across retries of the same event — use it to deduplicate at-least-once deliveries.
  • webhook-timestamp: Unix timestamp in seconds at which this delivery attempt was signed.
  • webhook-signature: Signature in the form v1,<base64> (see below).
  • request-id (and correlation-id when available): tracing ids you can quote to support.

Signature Verification

Deliveries are signed following the Standard Webhooks specification — verify them with an official standardwebhooks library for your language, passing your endpoint's secret (the full whsec_... string) and the three webhook-* headers.

Verifying manually instead: the signature is an HMAC-SHA256 over the string {webhook-id}.{webhook-timestamp}.{raw_body} — the three parts joined with a literal dot, where raw_body is the exact request body bytes as received (do not re-serialize the JSON). The HMAC key is the secret after stripping the whsec_ prefix and base64-decoding the remainder.

key            = base64_decode( secret without the "whsec_" prefix )
signed_content = webhook_id + "." + webhook_timestamp + "." + raw_body
expected       = "v1," + base64( hmac_sha256( key, utf8_bytes(signed_content) ) )
valid          = constant_time_compare(expected, webhook_signature_header)

To protect against replay, also reject deliveries whose webhook-timestamp is outside your tolerance window (5 minutes is a common choice).

The secret is returned exactly once — on endpoint creation and on secret rotation.

Body shape

Every delivery has the same envelope: type (the event type), id, event_id, timestamp, payload_version, tenant_id, optional actor and request, and data. The resource itself is at data.object, and data.previous_attributes carries the old values of whatever an edit changed.

data.object always identifies the resource, and within one payload_version its fields are only ever added to — never removed, renamed or retyped. Treat the key set as open and ignore keys you do not recognise.

List subscribable webhook event types

Returns every event type this workspace can subscribe to, as <resource path>.<verb>.

Subscribe to exact names or to patterns: a trailing * after any path prefix (folder.*), a leading * for one verb across all resources (*.created), or * for everything. A wildcard verb widens the path to a prefix; a named verb pins it exactly — so folder.* also matches folder.permissions.updated, while folder.updated does not.

The list is tenant-scoped because it includes one set of event types per custom-object definition, which is the main reason to fetch it at runtime rather than hard-coding it.

Authorizations:
BearerAuth

Responses

Response samples

Content type
application/json

EventTypes

{
  • "items": [
    ]
}

MCP Server

Manage MCP server settings for the tenant. Controls whether MCP is enabled and which operations are allowed.

Get MCP server settings

Returns the current MCP server operating mode and connection URL for this tenant.

Authorizations:
BearerAuth

Responses

Response samples

Content type
application/json

ReadOnlyMcpSettings

{}

Update MCP server settings

Partially updates the MCP server settings. Omit a field to leave it unchanged. Set mode to OFF to disable MCP entirely, READ_ONLY to allow read operations only, or READ_WRITE to allow all operations.

Authorizations:
BearerAuth
Request Body schema: application/merge-patch+json
required
mode
string
Enum: "OFF" "READ_ONLY" "READ_WRITE"

New operating mode. Omit to leave unchanged; explicit null is rejected (422).

Responses

Request samples

Content type
application/merge-patch+json

EnableReadOnlyMcp

{
  • "mode": "READ_ONLY"
}

Response samples

Content type
application/json

UpdatedReadOnlyMcpSettings

{}

Custom Object Instances

API for managing custom object instances

Get a custom object instance

Retrieves a custom object instance by ID

Authorizations:
BearerAuth
path Parameters
definition_slug
required
string

Slug of the custom-object definition.

instance_id
required
string <uuid>

UUID of the custom-object instance.

Responses

Response samples

Content type
application/json

EquipmentInstance

{
  • "schema": {
    },
  • "data": {
    },
  • "display_value": "Rooftop HVAC Unit RTU-17 · AFS-RTU-17",
  • "lock_version": 0
}

Update a custom object instance

Updates an existing custom object instance

Authorizations:
BearerAuth
path Parameters
definition_slug
required
string

Slug of the custom-object definition.

instance_id
required
string <uuid>

UUID of the custom-object instance.

Request Body schema: application/json
required
required
object

Updated instance data as key-value pairs

lock_version
integer <int64>

Optimistic-locking version: validated when provided (409 on mismatch); omitting it skips the concurrency check

Responses

Request samples

Content type
application/json

ReplaceEquipmentInstance

{
  • "lock_version": 2,
  • "data": {
    }
}

Response samples

Content type
application/json

ReplacedEquipmentInstance

{
  • "schema": {
    },
  • "data": {
    },
  • "display_value": "Rooftop HVAC Unit RTU-17 · AFS-RTU-17",
  • "lock_version": 3
}

Delete a custom object instance

Deletes a custom object instance by ID

Authorizations:
BearerAuth
path Parameters
definition_slug
required
string

Slug of the custom-object definition.

instance_id
required
string <uuid>

UUID of the custom-object instance.

Responses

Response samples

Content type
application/problem+json
{
  • "title": "Validation failed",
  • "status": 422,
  • "detail": "One or more fields failed validation",
  • "instance": "string",
  • "errors": [
    ],
  • "data": {
    }
}

Create custom object instances

Creates one or more instances of one or more custom object definitions, and the associations between them, in a single transaction. Each association references its sides either by *_instance_key (an in-request reference to a key carried by another instances[] item) or by *_instance_id (an existing instance).

Authorizations:
BearerAuth
Request Body schema: application/json
required
required
Array of objects (BatchCreateInstanceItem)

Instances to create

Array of objects (BatchAssociationItem)

Associations between the instances and/or existing instances

Responses

Request samples

Content type
application/json

BatchCreateEquipment

{
  • "instances": [
    ]
}

Response samples

Content type
application/json

CreatedEquipmentBatch

{
  • "instances": [
    ]
}

List all instances of a definition

Retrieves all instances of a custom object definition

Authorizations:
BearerAuth
path Parameters
definition_slug
required
string

Slug of the custom-object definition.

query Parameters
page
integer >= 0
Default: 0

Page number (0-based).

size
integer [ 1 .. 100 ]
Default: 10
Example: size=10

Number of items per page (max 100).

Responses

Response samples

Content type
application/json

EquipmentPage

{
  • "items": [
    ],
  • "schema": {
    },
  • "page": {
    }
}

List associated instances

Retrieves instances associated with a specific instance via a relation

Authorizations:
BearerAuth
path Parameters
definition_slug
required
string

Slug of the custom-object definition.

instance_id
required
string <uuid>

UUID of the custom-object instance.

relation_slug
required
string

Slug of the custom-object relation.

Responses

Response samples

Content type
application/json

EquipmentMaintenanceRequests

{
  • "items": [
    ],
  • "schema": {
    },
  • "page": {
    }
}

Deleted Events

    Delete event tracking for CDC-style incremental sync with delete detection.
    
    This endpoint allows external systems (e.g., Airbyte connectors) to poll for entity deletions 
    within a time range, enabling downstream systems to remove stale records.
    
    Events are retained for 28 days before automatic cleanup.

List deleted events

        Returns a paginated list of delete events within the specified time range.
        
        Use this endpoint for CDC-style incremental sync to detect which entities have been deleted.
        Events are sorted by `deleted_at` (ascending) with secondary sort by `id` for deterministic pagination.
        
        **Cursor-based incremental sync:**
        - Use `deleted_at` as the cursor field
        - On first sync, use a `deleted_from` timestamp in the past and `deleted_to` as current time
        - On subsequent syncs, use the last `deleted_at` value from the previous sync as the new `deleted_from`
    
Authorizations:
BearerAuth
query Parameters
deleted_from
required
string <date-time>
Example: deleted_from=2024-01-01T00:00:00Z

Lower bound for deleted_at (inclusive, RFC 3339).

deleted_to
required
string <date-time>
Example: deleted_to=2024-01-02T00:00:00Z

Upper bound for deleted_at (exclusive, RFC 3339).

entity_type
string
Example: entity_type=user

Filter by entity type (e.g., user, vehicle, tour). If not specified, returns all entity types.

page
integer >= 0
Default: 0

Page number (0-based).

size
integer [ 1 .. 1000 ]
Default: 100
Example: size=100

Number of elements per page (max 1000). The cap is deliberately higher than the platform default of 100 because sync-style consumers replay deletions in bulk.

Responses

Response samples

Content type
application/json

DeletedEventsListResponse

{
  • "items": [
    ],
  • "page": {
    }
}

Document Management

Document management API.

List a folder's access-control entries

Returns the entries stored directly on the folder (one per principal: everyone / role / user), for rendering the permissions editor. For a top-level folder with no entries of its own, the tenant-wide default matrix it effectively resolves to is returned instead, flagged via from_tenant_default. An empty list on a non-root folder means it inherits its parent. Requires the documents:read grant to reach the feature and, per folder, either the documents:edit_permissions grant or ownership — otherwise 403.

Authorizations:
BearerAuth
path Parameters
folder_id
required
string <uuid>

UUID of the folder.

Responses

Response samples

Content type
application/json

EquipmentManualPermissions

{
  • "folder_id": "00000000-0000-4000-8000-000000007001",
  • "entries": [
    ],
  • "inherited": false
}

Update a folder's access-control entries

Stores the supplied entries as the folder's complete set (a replace, not a merge); an empty list clears them so the folder inherits. everyone may coexist with role/user entries. Requires the documents:read grant plus, per folder, the documents:edit_permissions grant or ownership. Returns the saved entries.

Authorizations:
BearerAuth
path Parameters
folder_id
required
string <uuid>

UUID of the folder.

Request Body schema: application/json
required
required
Array of objects (PermissionEntryInput)

The complete list of entries the folder should have after this call.

Array
principal_type
required
string
Enum: "everyone" "role" "user"
role_name
string

Required when principal_type is role.

user_id
string <uuid>

Required when principal_type is user.

level
required
string
Enum: "read" "write"

Access level to grant.

Responses

Request samples

Content type
application/json
Example

ReplaceEquipmentManualPermissions

{
  • "entries": [
    ]
}

Response samples

Content type
application/json

ReplacedEquipmentManualPermissions

{
  • "folder_id": "00000000-0000-4000-8000-000000007001",
  • "entries": [
    ],
  • "inherited": false
}

List a document's own access-control entries

Returns the entries stored directly on the document (one per principal: everyone / role / user), for rendering the permissions editor. An empty list means the document has no override and inherits its folder. Requires the documents:read grant to reach the feature and, per document, permission-management rights (the document's creator, the owning folder's manager, or the documents:edit_permissions grant) — otherwise 403.

Authorizations:
BearerAuth
path Parameters
document_id
required
string <uuid>

UUID of the document.

Responses

Response samples

Content type
application/json

ServiceManualPermissions

{
  • "document_id": "00000000-0000-4000-8000-000000007101",
  • "entries": [
    ],
  • "inherited": false
}

Update a document's own access-control entries

Stores the supplied entries as the document's complete override set (a replace, not a merge); an empty list clears the override so the document inherits its folder again. everyone may coexist with role/user entries. Requires the documents:read grant plus, per document, permission-management rights (the document's creator, the owning folder's manager, or the documents:edit_permissions grant). Returns the saved entries.

Authorizations:
BearerAuth
path Parameters
document_id
required
string <uuid>

UUID of the document.

Request Body schema: application/json
required
required
Array of objects (PermissionEntryInput)

The complete list of entries the document should have after this call.

Array
principal_type
required
string
Enum: "everyone" "role" "user"
role_name
string

Required when principal_type is role.

user_id
string <uuid>

Required when principal_type is user.

level
required
string
Enum: "read" "write"

Access level to grant.

Responses

Request samples

Content type
application/json
Example

ReplaceServiceManualPermissions

{
  • "entries": [
    ]
}

Response samples

Content type
application/json

ReplacedServiceManualPermissions

{
  • "document_id": "00000000-0000-4000-8000-000000007101",
  • "entries": [
    ],
  • "inherited": false
}

List folders (paginated)

Returns folders that are direct children of parent_id (or root folders when parent_id is omitted), paginated in ascending name order. Default page size is 20, capped at 100. Folders of kind = managed_branch whose namespace is owned by a registered managed-folder provider are auto-expanded: the response surfaces one folder per managed subject at this depth, lazy-creating any missing rows. The provider's order is authoritative for managed pages. Requires the documents:read grant.

Authorizations:
BearerAuth
query Parameters
parent_id
string <uuid>

Parent folder id; omit for root listing.

page
integer >= 0
Default: 0

Page number (0-based).

size
integer [ 1 .. 100 ]
Default: 20
Example: size=20

Number of items per page (max 100).

Responses

Response samples

Content type
application/json

AlpineRootFolders

{
  • "items": [
    ],
  • "page": {
    }
}

Create a folder

Creates a folder under the given parent (or at the root if no parent is supplied). Requires the documents:create grant.

Authorizations:
BearerAuth
Request Body schema: application/json
required
name
required
string

Display name of the folder. Validated server-side: NFC-normalized, max 255 codepoints, no path separators / control chars / Windows-reserved characters, not a reserved name.

parent_id
string <uuid>

Parent folder id. Omit for a top-level folder.

Responses

Request samples

Content type
application/json

CreateEquipmentManualsFolder

{
  • "name": "Equipment manuals"
}

Response samples

Content type
application/json

CreatedEquipmentManualsFolder

{
  • "id": "00000000-0000-4000-8000-000000008001",
  • "lock_version": 0,
  • "name": "Equipment manuals",
  • "display_name": "Equipment manuals",
  • "kind": "user",
  • "created_at": "2026-08-20T08:15:00Z",
  • "created_by": "00000000-0000-4000-8000-000000000102",
  • "created_by_name": "Jonas Leitner",
  • "access_level": "manage",
  • "tags": [
    ]
}

Star a folder for the calling user

Idempotent: re-starring a folder is a no-op and returns the same detail response with starred=true. Requires the documents:update grant.

Authorizations:
BearerAuth
path Parameters
folder_id
required
string <uuid>

UUID of the folder.

Responses

Response samples

Content type
application/json

StarredEquipmentManualsFolder

{
  • "id": "00000000-0000-4000-8000-000000008001",
  • "lock_version": 0,
  • "name": "Equipment manuals",
  • "display_name": "Equipment manuals",
  • "kind": "user",
  • "created_at": "2026-08-20T08:15:00Z",
  • "created_by": "00000000-0000-4000-8000-000000000102",
  • "created_by_name": "Jonas Leitner",
  • "starred": true,
  • "access_level": "manage",
  • "tags": [
    ]
}

Unstar a folder for the calling user

Idempotent: un-starring a folder that was not starred is a no-op. Returns the folder detail with starred=false. Requires the documents:update grant.

Authorizations:
BearerAuth
path Parameters
folder_id
required
string <uuid>

UUID of the folder.

Responses

Response samples

Content type
application/json

UnstarredEquipmentManualsFolder

{
  • "id": "00000000-0000-4000-8000-000000008001",
  • "lock_version": 0,
  • "name": "Equipment manuals",
  • "display_name": "Equipment manuals",
  • "kind": "user",
  • "created_at": "2026-08-20T08:15:00Z",
  • "created_by": "00000000-0000-4000-8000-000000000102",
  • "created_by_name": "Jonas Leitner",
  • "starred": false,
  • "access_level": "manage",
  • "tags": [
    ]
}

Submit a document version for AI extraction

Asynchronously extracts structured fields from the version. The call returns immediately with a document-management extraction id. Clients should listen for events.documents SSE lifecycle events and may poll GET /documents/extractions/{extraction_id} as a fallback until the status reaches a terminal state. Each call appends a new extraction (re-analysis is supported by submitting again). Terminal payloads are copied into document-management before the analyzer job is acked. Requires the documents:update grant.

Authorizations:
BearerAuth
path Parameters
document_id
required
string <uuid>

UUID of the document.

version_id
required
string <uuid>

UUID of the document version.

Responses

Response samples

Content type
application/json

Rtu17AnalysisAccepted

{
  • "extraction_id": "00000000-0000-4000-8000-000000008005",
  • "status": "pending"
}

Start a new version upload (replace) on an existing document

Creates a new draft [DocumentVersion] with version_number = max + 1, returns a presigned upload form. The current version pointer does NOT change until POST /documents/{document_id}/finalize is called. Requires the documents:update grant.

Authorizations:
BearerAuth
path Parameters
document_id
required
string <uuid>

UUID of the document.

Request Body schema: application/json
required
mime_type
required
string non-empty

MIME type of the file being uploaded. Must equal the document's current MIME type — uploading a different content type creates a different document, not a new version. Mismatches are rejected with document-management/version-mime-mismatch.

original_file_name
string

Filename of the file being uploaded (e.g. Invoice-2026-Q2-revised.pdf). Stored on the version row so the UI can list uploads with their actual filenames. Falls back to the document's name when omitted.

change_note
string

Optional free-form note describing what's new in this version. Stored on the version row.

Responses

Request samples

Content type
application/json

UploadRtu17ManualRevision

{
  • "mime_type": "application/pdf",
  • "original_file_name": "RTU-17-service-manual-rev-2.pdf",
  • "change_note": "Added the revised filter replacement schedule."
}

Response samples

Content type
application/json

Rtu17ManualRevisionUploadIntent

{
  • "document_id": "00000000-0000-4000-8000-000000008002",
  • "version_id": "00000000-0000-4000-8000-000000008004",
  • "upload": {
    }
}

Star a document for the calling user

Idempotent: re-starring a document is a no-op and returns the same detail response with starred=true. Requires the documents:update grant.

Authorizations:
BearerAuth
path Parameters
document_id
required
string <uuid>

UUID of the document.

Responses

Response samples

Content type
application/json

StarredRtu17ServiceManual

{
  • "id": "00000000-0000-4000-8000-000000008002",
  • "lock_version": 1,
  • "folder_id": "00000000-0000-4000-8000-000000008001",
  • "name": "RTU-17 service manual.pdf",
  • "description": "Manufacturer service manual for rooftop unit RTU-17.",
  • "current_version_id": "00000000-0000-4000-8000-000000008004",
  • "size": 248320,
  • "mime_type": "application/pdf",
  • "created_at": "2026-08-20T08:30:00Z",
  • "created_by": "00000000-0000-4000-8000-000000000102",
  • "created_by_name": "Jonas Leitner",
  • "starred": true,
  • "preview_available": true,
  • "access_level": "manage",
  • "tags": [
    ]
}

Unstar a document for the calling user

Idempotent: un-starring a document that was not starred is a no-op. Returns the document detail with starred=false. Requires the documents:update grant.

Authorizations:
BearerAuth
path Parameters
document_id
required
string <uuid>

UUID of the document.

Responses

Response samples

Content type
application/json

UnstarredRtu17ServiceManual

{
  • "id": "00000000-0000-4000-8000-000000008002",
  • "lock_version": 1,
  • "folder_id": "00000000-0000-4000-8000-000000008001",
  • "name": "RTU-17 service manual.pdf",
  • "description": "Manufacturer service manual for rooftop unit RTU-17.",
  • "current_version_id": "00000000-0000-4000-8000-000000008004",
  • "size": 248320,
  • "mime_type": "application/pdf",
  • "created_at": "2026-08-20T08:30:00Z",
  • "created_by": "00000000-0000-4000-8000-000000000102",
  • "created_by_name": "Jonas Leitner",
  • "starred": false,
  • "preview_available": true,
  • "access_level": "manage",
  • "tags": [
    ]
}

Soft-delete a document (move to Trash)

Soft-deletes the document — the row is moved to the user's Trash and can be restored later. The captured original_path text is recorded so the restore flow can put the document back where it came from. Idempotent. Hard-delete (permanent removal) is DELETE /documents/{document_id} and is only allowed on rows that have already been soft-deleted. Requires the documents:delete grant.

Authorizations:
BearerAuth
path Parameters
document_id
required
string <uuid>

UUID of the document.

Responses

Response samples

Content type
application/json

TrashedRtu17ServiceManual

{
  • "id": "00000000-0000-4000-8000-000000008002",
  • "lock_version": 2,
  • "name": "RTU-17 service manual.pdf",
  • "description": "Manufacturer service manual for rooftop unit RTU-17.",
  • "current_version_id": "00000000-0000-4000-8000-000000008004",
  • "size": 248320,
  • "mime_type": "application/pdf",
  • "created_at": "2026-08-20T08:30:00Z",
  • "created_by": "00000000-0000-4000-8000-000000000102",
  • "created_by_name": "Jonas Leitner",
  • "soft_deleted_at": "2026-08-20T10:00:00Z",
  • "soft_deleted_by": "00000000-0000-4000-8000-000000000102",
  • "original_path": "/Equipment manuals/",
  • "access_level": "manage",
  • "tags": [
    ]
}

Restore a soft-deleted document

Restores a soft-deleted document from the Trash. The optional request body lets the caller pick the destination and the conflict-resolution strategy. Target folder: when target_folder_id is supplied, the document is restored into that folder (must exist and be user or managed). When omitted, the captured original_path is walked through the live tree and any missing folders are auto-created as user folders so the document reappears at its original location. Conflict resolution (when a live sibling already has the same name): rename uses the supplied new_name for the restored document; new_version appends the restored document's current version as a new version of the existing live sibling and hard-deletes the soft-deleted row (the MIME types must match — otherwise 422 version-mime-mismatch). When conflict_resolution is omitted and a name collision exists, the call rejects with 409 name-taken. Requires the documents:update grant.

Authorizations:
BearerAuth
path Parameters
document_id
required
string <uuid>

UUID of the document.

Request Body schema: application/json
target_folder_id
string <uuid>

Folder to restore into. Omit to use the document's captured original_path (auto-creates missing folders).

conflict_resolution
string
Enum: "rename" "new_version"

How to handle a name collision in the target folder. Allowed: rename (uses new_name), new_version (appends as new version of the live sibling). Omit to fail with 409 on collision.

new_name
string

Replacement name. Required when conflict_resolution = "rename"; ignored otherwise.

Responses

Request samples

Content type
application/json
Example

RestoreToEquipmentManuals

{
  • "target_folder_id": "00000000-0000-4000-8000-000000008001"
}

Response samples

Content type
application/json

RestoredRtu17ServiceManual

{
  • "id": "00000000-0000-4000-8000-000000008002",
  • "lock_version": 1,
  • "folder_id": "00000000-0000-4000-8000-000000008001",
  • "name": "RTU-17 service manual.pdf",
  • "description": "Manufacturer service manual for rooftop unit RTU-17.",
  • "current_version_id": "00000000-0000-4000-8000-000000008004",
  • "size": 248320,
  • "mime_type": "application/pdf",
  • "created_at": "2026-08-20T08:30:00Z",
  • "created_by": "00000000-0000-4000-8000-000000000102",
  • "created_by_name": "Jonas Leitner",
  • "access_level": "manage",
  • "tags": [
    ]
}

Finalize a document upload

Completes the latest pending upload for the given document, populates the version's size and MIME type from the filestore rendition, and points current_version_id at it. Idempotent only when called more than once for the same upload — for replacing an existing version, use POST /documents/{document_id}/versions/initiate-upload (slice 3b-ii). Requires the documents:create grant.

Authorizations:
BearerAuth
path Parameters
document_id
required
string <uuid>

UUID of the document.

Responses

Response samples

Content type
application/json

FinalizedRtu17ServiceManual

{
  • "id": "00000000-0000-4000-8000-000000008002",
  • "lock_version": 1,
  • "folder_id": "00000000-0000-4000-8000-000000008001",
  • "name": "RTU-17 service manual.pdf",
  • "description": "Manufacturer service manual for rooftop unit RTU-17.",
  • "current_version_id": "00000000-0000-4000-8000-000000008004",
  • "size": 248320,
  • "mime_type": "application/pdf",
  • "created_at": "2026-08-20T08:30:00Z",
  • "created_by": "00000000-0000-4000-8000-000000000102",
  • "created_by_name": "Jonas Leitner",
  • "access_level": "manage",
  • "tags": [
    ]
}

Start a new document upload

Creates a draft document and a draft version, then returns a presigned upload form. The client POSTs the binary content to the form URL, then calls POST /documents/{document_id}/finalize to complete the upload. Until finalize succeeds, the document's current_version_id is null. Requires the documents:create grant.

Authorizations:
BearerAuth
Request Body schema: application/json
required
name
required
string

Display name of the document. Validated server-side: NFC-normalized, max 255 codepoints, no path separators / control chars / Windows-reserved characters, not a reserved name.

folder_id
required
string <uuid>

Folder this document will live in.

mime_type
required
string

MIME type of the file being uploaded.

Responses

Request samples

Content type
application/json

UploadRtu17ServiceManual

{
  • "name": "RTU-17 service manual.pdf",
  • "folder_id": "00000000-0000-4000-8000-000000008001",
  • "mime_type": "application/pdf"
}

Response samples

Content type
application/json

Rtu17ManualUploadIntent

{
  • "document_id": "00000000-0000-4000-8000-000000008002",
  • "version_id": "00000000-0000-4000-8000-000000008003",
  • "upload": {
    }
}

Read tenant-scoped document-management settings

Returns the active document-management settings for the calling tenant. Currently the only setting is auto_hard_delete_after_days, which drives the daily auto-hard-delete cron. Requires the documents:read grant.

Authorizations:
BearerAuth

Responses

Response samples

Content type
application/json

AlpineDocumentRetention

{
  • "auto_hard_delete_after_days": 45
}

Update tenant-scoped document-management settings (JSON merge patch)

JSON merge patch semantics: a field present in the body is applied; an absent field is left unchanged. auto_hard_delete_after_days must be an integer in the inclusive range 1..180. Out-of-range values produce 422 with document-management/invalid-retention-days. Requires the documents:settings:update grant.

Authorizations:
BearerAuth
Request Body schema: application/merge-patch+json
required
auto_hard_delete_after_days
integer <int32> [ 1 .. 180 ]

Number of days after which a soft-deleted document is permanently removed. Must be in the inclusive range 1..180. Field omitted leaves the value unchanged; explicit null is rejected (the field is required and cannot be cleared).

Responses

Request samples

Content type
application/merge-patch+json

SetDocumentRetention

{
  • "auto_hard_delete_after_days": 45
}

Response samples

Content type
application/json

UpdatedAlpineDocumentRetention

{
  • "auto_hard_delete_after_days": 45
}

Get a folder by id

Returns the folder with the given id. Requires the documents:read grant.

Authorizations:
BearerAuth
path Parameters
folder_id
required
string <uuid>

UUID of the folder.

Responses

Response samples

Content type
application/json

EquipmentManualsFolder

{
  • "id": "00000000-0000-4000-8000-000000008001",
  • "lock_version": 0,
  • "name": "Equipment manuals",
  • "display_name": "Equipment manuals",
  • "kind": "user",
  • "created_at": "2026-08-20T08:15:00Z",
  • "created_by": "00000000-0000-4000-8000-000000000102",
  • "created_by_name": "Jonas Leitner",
  • "starred": true,
  • "access_level": "manage",
  • "tags": [
    ]
}

Delete a folder and soft-delete every contained document

Hard-deletes the folder and any subfolders. Every contained document is soft-deleted as part of the same operation — its original_path (the human-readable folder path text it lived at) is captured so the user can restore it individually later from the Trash. Folders themselves are NEVER soft-deleted: they are simply removed from the live tree. Managed (managed/managed_branch) folders cannot be deleted directly. Requires the documents:delete grant.

Authorizations:
BearerAuth
path Parameters
folder_id
required
string <uuid>

UUID of the folder.

Responses

Response samples

Content type
application/problem+json
{
  • "title": "Validation failed",
  • "status": 422,
  • "detail": "One or more fields failed validation",
  • "instance": "string",
  • "errors": [
    ],
  • "data": {
    }
}

Rename and/or move a folder (JSON merge patch)

JSON merge patch semantics: a field present in the body is applied; an absent field is left unchanged. To move a folder under a new parent, send parent_id as a UUID. To move it to the root, send parent_id: null explicitly. Cycles (moving into self or a descendant) are rejected; descendant paths are rebuilt in the same transaction. Requires the documents:update grant.

Authorizations:
BearerAuth
path Parameters
folder_id
required
string <uuid>

UUID of the folder.

Request Body schema: application/merge-patch+json
required
lock_version
integer or null <int64>

Optimistic-locking version: validated when provided (409 on mismatch); omitting it skips the concurrency check

name
string

New folder name. Validation rules: trimmed, NFC-normalized, 1..255 codepoints, no slashes/backslashes/control characters, not a Windows reserved name. Omitted leaves the value unchanged; explicit null is rejected (422) — name is required and cannot be cleared.

parent_id
string or null <uuid>

New parent folder id, or null to move to root. Omit to leave the parent unchanged. Cannot move into the folder itself or any of its descendants. Cannot move a managed folder.

tag_ids
Array of strings or null <uuid> unique [ items <uuid > ]

Replacement set of tag ids. Field omitted leaves tags unchanged; [] or null clears all tags; a non-empty array replaces the current set (server diffs against existing associations). All ids must reference existing tags. Rejected on managed folders.

Responses

Request samples

Content type
application/merge-patch+json
Example

RenameAndTagFolder

{
  • "lock_version": 0,
  • "name": "Equipment manuals",
  • "tag_ids": [
    ]
}

Response samples

Content type
application/json

UpdatedEquipmentManualsFolder

{
  • "id": "00000000-0000-4000-8000-000000008001",
  • "lock_version": 0,
  • "name": "Equipment manuals",
  • "display_name": "Equipment manuals",
  • "kind": "user",
  • "created_at": "2026-08-20T08:15:00Z",
  • "created_by": "00000000-0000-4000-8000-000000000102",
  • "created_by_name": "Jonas Leitner",
  • "access_level": "manage",
  • "tags": [
    ]
}

Get a document by id

Returns the document with the given id (soft-deleted documents are returned with soft_deleted_at set). Requires the documents:read grant.

Authorizations:
BearerAuth
path Parameters
document_id
required
string <uuid>

UUID of the document.

Responses

Response samples

Content type
application/json

Rtu17ServiceManualDetail

{
  • "id": "00000000-0000-4000-8000-000000008002",
  • "lock_version": 1,
  • "folder_id": "00000000-0000-4000-8000-000000008001",
  • "name": "RTU-17 service manual.pdf",
  • "description": "Manufacturer service manual for rooftop unit RTU-17.",
  • "current_version_id": "00000000-0000-4000-8000-000000008004",
  • "size": 248320,
  • "mime_type": "application/pdf",
  • "created_at": "2026-08-20T08:30:00Z",
  • "created_by": "00000000-0000-4000-8000-000000000102",
  • "created_by_name": "Jonas Leitner",
  • "starred": true,
  • "preview_available": true,
  • "access_level": "manage",
  • "tags": [
    ]
}

Permanently delete a soft-deleted document (hard-delete)

Hard-deletes a soft-deleted document and all its versions. Cannot be called on a live row — soft-delete it first via POST /documents/{document_id}/soft-delete. Filestore blob cleanup is wired up in a later slice. Requires the documents:delete grant.

Authorizations:
BearerAuth
path Parameters
document_id
required
string <uuid>

UUID of the document.

Responses

Response samples

Content type
application/problem+json
{
  • "title": "Validation failed",
  • "status": 422,
  • "detail": "One or more fields failed validation",
  • "instance": "string",
  • "errors": [
    ],
  • "data": {
    }
}

Rename, move, and/or update the description of a document (JSON merge patch)

JSON merge patch semantics: a field present in the body is applied; an absent field is left unchanged. Send description: null explicitly to clear the description. Send folder_id to move the document into another folder atomically — the target must be live and have kind = user or kind = managed (managed leaf); managed_branch is rejected. Name collision is checked against the target folder's siblings when a move is requested. Requires the documents:update grant.

Authorizations:
BearerAuth
path Parameters
document_id
required
string <uuid>

UUID of the document.

Request Body schema: application/merge-patch+json
required
lock_version
integer or null <int64>

Optimistic-locking version: validated when provided (409 on mismatch); omitting it skips the concurrency check

name
string

New document name. Validation rules match folder names (1..255 codepoints, no slashes/backslashes/control characters, not a Windows reserved name). Omitted leaves the value unchanged; explicit null is rejected (422) — name is required and cannot be cleared.

description
string or null

Free-form description. Send null to clear; omit to leave unchanged.

folder_id
string <uuid>

Move the document into the folder with this id. Target must be live and have kind = user or kind = managed (managed leaf). managed_branch targets are rejected. Targeting a managed leaf that has not been materialised yet lazy-creates it. Omit to leave the folder unchanged; explicit null is rejected (422).

tag_ids
Array of strings or null <uuid> unique [ items <uuid > ]

Replacement set of tag ids. Field omitted leaves tags unchanged; [] or null clears all tags; a non-empty array replaces the current set (server diffs against existing associations). All ids must reference existing tags.

Responses

Request samples

Content type
application/merge-patch+json
Example

DescribeAndTagRtu17Manual

{
  • "lock_version": 0,
  • "description": "Manufacturer service manual for rooftop unit RTU-17.",
  • "tag_ids": [
    ]
}

Response samples

Content type
application/json

UpdatedRtu17ServiceManual

{
  • "id": "00000000-0000-4000-8000-000000008002",
  • "lock_version": 1,
  • "folder_id": "00000000-0000-4000-8000-000000008001",
  • "name": "RTU-17 service manual.pdf",
  • "description": "Manufacturer service manual for rooftop unit RTU-17.",
  • "current_version_id": "00000000-0000-4000-8000-000000008004",
  • "size": 248320,
  • "mime_type": "application/pdf",
  • "created_at": "2026-08-20T08:30:00Z",
  • "created_by": "00000000-0000-4000-8000-000000000102",
  • "created_by_name": "Jonas Leitner",
  • "access_level": "manage",
  • "tags": [
    ]
}

Read document-management usage snapshot

Returns a lightweight usage snapshot for the calling tenant: live and soft-deleted document counts. Available even when the document-management feature flag is off; used by the gated-tenant upgrade page. Usage and quotas live under the generic usage endpoints. Requires the documents:read grant.

Authorizations:
BearerAuth

Responses

Response samples

Content type
application/json

AlpineDocumentUsage

{
  • "document_count": 24,
  • "soft_deleted_document_count": 2
}

List the calling user's starred folders and documents (paginated)

Returns a single mixed list sorted by starred_at desc, paginated. Each entry's kind field is "folder" or "document"; the corresponding folder or document field is populated. Soft-deleted items are excluded — see GET /soft-deleted for the user's Trash listing. Default page size is 20, capped at 100. Requires the documents:read grant.

Authorizations:
BearerAuth
query Parameters
page
integer >= 0
Default: 0

Page number (0-based).

size
integer [ 1 .. 100 ]
Default: 20
Example: size=20

Number of items per page (max 100).

Responses

Response samples

Content type
application/json

AlpineStarredDocuments

{
  • "items": [
    ],
  • "page": {
    }
}

List the tenant's soft-deleted documents (paginated)

Returns soft-deleted documents (the user's Trash) sorted by soft_deleted_at desc, paginated. Each entry's kind field is always "document" (folders are never soft-deleted in the new model). The corresponding document field is populated and includes the captured original_path text. Default page size is 20, capped at 100. Tenant-wide and gated by the grant only: a soft-deleted document has no live folder (its folder_id is severed on delete), so per-folder ACL filtering cannot apply here. Requires the documents:read grant.

Authorizations:
BearerAuth
query Parameters
page
integer >= 0
Default: 0

Page number (0-based).

size
integer [ 1 .. 100 ]
Default: 20
Example: size=20

Number of items per page (max 100).

Responses

Response samples

Content type
application/json

AlpineDocumentTrash

{
  • "items": [
    ],
  • "page": {
    }
}

Look up a folder by its display path

Walks the tree from the root, matching slash-separated name segments (NFC and case-insensitive). Returns 404 if any segment doesn't match a folder. Requires the documents:read grant.

Authorizations:
BearerAuth
query Parameters
path
required
string

Slash-separated display path, e.g. /Inspection reports/2024.

Responses

Response samples

Content type
application/json

EquipmentManualsFolderByPath

{
  • "id": "00000000-0000-4000-8000-000000008001",
  • "lock_version": 0,
  • "name": "Equipment manuals",
  • "display_name": "Equipment manuals",
  • "kind": "user",
  • "created_at": "2026-08-20T08:15:00Z",
  • "created_by": "00000000-0000-4000-8000-000000000102",
  • "created_by_name": "Jonas Leitner",
  • "starred": true,
  • "access_level": "manage",
  • "tags": [
    ]
}

List documents in a folder (paginated)

Returns documents directly in the given folder (not the subtree), paginated. Soft-deleted documents are never returned here — they live under the dedicated /soft-deleted endpoint. Sortable fields: name, createdAt, updatedAt, size. Default sort is name:asc; default page size is 20, capped at 100. Requires the documents:read grant.

Authorizations:
BearerAuth
query Parameters
folder_id
required
string <uuid>

Folder id.

page
integer >= 0
Default: 0

Page number (0-based).

size
integer [ 1 .. 100 ]
Default: 20
Example: size=20

Number of items per page (max 100).

sort
Array of strings
Example: sort=updated_at:desc

Repeated sorting criteria in field:direction format. Allowed fields: name, created_at, updated_at, size. Default: name:asc.

Responses

Response samples

Content type
application/json

EquipmentManualDocuments

{
  • "items": [
    ],
  • "page": {
    }
}

List all versions of a document

Returns every version, newest first. Pending (not-yet-finalized) versions have finalized_at = null. Requires the documents:read grant.

Authorizations:
BearerAuth
path Parameters
document_id
required
string <uuid>

UUID of the document.

Responses

Response samples

Content type
application/json

Rtu17ManualVersions

[
  • {
    }
]

List extractions for a document version

Returns up to 50 extractions for the version, newest first. Requires the documents:read grant.

Authorizations:
BearerAuth
path Parameters
document_id
required
string <uuid>

UUID of the document.

version_id
required
string <uuid>

UUID of the document version.

Responses

Response samples

Content type
application/json

Rtu17ExtractionHistory

{
  • "items": [
    ]
}

Get the most recent succeeded extraction for a document version

Convenience endpoint: returns the latest extraction whose status is succeeded. Returns 404 (slug extraction-not-found) when no extraction has succeeded yet for this version. Requires the documents:read grant.

Authorizations:
BearerAuth
path Parameters
document_id
required
string <uuid>

UUID of the document.

version_id
required
string <uuid>

UUID of the document version.

Responses

Response samples

Content type
application/json

LatestRtu17Extraction

{
  • "id": "00000000-0000-4000-8000-000000008005",
  • "document_id": "00000000-0000-4000-8000-000000008002",
  • "version_id": "00000000-0000-4000-8000-000000008004",
  • "status": "succeeded",
  • "created_at": "2026-08-20T09:35:00Z",
  • "started_at": "2026-08-20T09:35:02Z",
  • "finished_at": "2026-08-20T09:35:08Z",
  • "schema": {
    },
  • "schema_inferred": true,
  • "extracted_fields": {
    }
}

Get a presigned download URL for a document version

Returns a short-lived presigned URL the client can GET to download the binary content. The URL is signed by the storage backend and expires after a few minutes. The optional rendition query parameter selects which filestore rendition to serve: original (default, the bytes the user uploaded) or preview (a JPEG inline preview, only available for image/PDF uploads when preview_available is true on the version). Requires the documents:read grant.

Authorizations:
BearerAuth
path Parameters
document_id
required
string <uuid>

UUID of the document.

version_id
required
string <uuid>

UUID of the document version.

query Parameters
rendition
string
Default: "original"
Enum: "original" "preview"

Rendition alias to serve. Defaults to original.

Responses

Response samples

Content type
application/json

Rtu17ManualDownload

List recently uploaded documents

Returns finalized, live documents sorted by their current version's uploaded_at descending. With folder_id the result is scoped to that folder's subtree (folder + descendants); without folder_id the listing is tenant-wide. Requires the documents:read grant.

Authorizations:
BearerAuth
query Parameters
folder_id
string <uuid>

Optional folder scope; when supplied, results are limited to the folder's subtree.

limit
integer [ 1 .. 100 ]
Default: 25

Maximum number of rows to return.

uploaded_after
string <date-time>

Strict RFC 3339 cutoff for the current version's uploaded_at; only documents uploaded after this instant are returned.

Responses

Response samples

Content type
application/json

RecentEquipmentDocuments

[
  • {
    }
]

Get an extraction by id

Returns the current durable document-management extraction state. Clients use this for an initial load, SSE-triggered refreshes, and polling fallback while an extraction is still running. Requires the documents:read grant.

Authorizations:
BearerAuth
path Parameters
extraction_id
required
string <uuid>

UUID of the document extraction.

Responses

Response samples

Content type
application/json

Rtu17Extraction

{
  • "id": "00000000-0000-4000-8000-000000008005",
  • "document_id": "00000000-0000-4000-8000-000000008002",
  • "version_id": "00000000-0000-4000-8000-000000008004",
  • "status": "succeeded",
  • "created_at": "2026-08-20T09:35:00Z",
  • "started_at": "2026-08-20T09:35:02Z",
  • "finished_at": "2026-08-20T09:35:08Z",
  • "schema": {
    },
  • "schema_inferred": true,
  • "extracted_fields": {
    }
}

Audit Log

Audit log management API. Audit logs can be queried and managed through these endpoints.

List audit logs

Retrieve audit logs with optional filters for time range, scope (USER or TENANT), event type (USER_CREATED or TENANT_CREATED), and actor. Requires 'audit-logs:read' grant.

Authorizations:
BearerAuth
query Parameters
occurred_from
string <date-time>
Example: occurred_from=2024-01-01T00:00:00Z

Lower bound for event occurrence time (inclusive, RFC 3339). Defaults to 1 day ago.

occurred_to
string <date-time>
Example: occurred_to=2024-12-31T23:59:59Z

Upper bound for event occurrence time (exclusive, RFC 3339). Defaults to now.

scope_type
string
Enum: "USER" "TENANT"
Example: scope_type=USER

Filter by scope type (USER or TENANT only)

scope_id
string
Example: scope_id=00000000-0000-4000-8000-000000001002

Filter by the ID of the affected entity (e.g., specific user ID, tour ID, case ID)

event_type
string
Enum: "USER_CREATED" "TENANT_CREATED"
Example: event_type=USER_CREATED

Filter by event type

actor_id
string
Example: actor_id=00000000-0000-4000-8000-000000001001

Filter by the ID of the actor who performed the action

page
integer >= 0
Default: 0

Page number (0-based). First page is 0.

size
integer [ 1 .. 1000 ]
Default: 50
Example: size=50

Number of items per page. Maximum allowed is 1000.

sort
Array of strings
Example: sort=scope_type:asc

Repeated sorting criteria in field:direction format. Allowed fields: id, original_event_time, scope_type, event_type, actor_id. Default: original_event_time:desc.

Responses

Response samples

Content type
application/json

AuditLogsResponse

{
  • "items": [
    ],
  • "page": {
    }
}

Areas

Geographic areas defined by polygons and optional zip ranges

List all areas

Returns a paginated list of areas. Requires the 'areas:read' grant.

Authorizations:
BearerAuth
query Parameters
page
integer >= 0
Default: 0

Page number (0-based).

size
integer [ 1 .. 100 ]
Default: 20
Example: size=20

Number of items per page (max 100).

Responses

Response samples

Content type
application/json

ServiceAreasPage

{
  • "items": [
    ],
  • "page": {
    }
}

Create an area

Requires the 'areas:create' grant.

Authorizations:
BearerAuth
Request Body schema: application/json
required
name
required
string

Display name of the area

description
string

Optional description

color
string

Hex color used to render the area overlay on maps

geo_json
required
any

GeoJSON Feature / FeatureCollection containing exactly one Polygon or MultiPolygon

Array of objects (ZipRange)

Optional postal-code ranges that fall inside this area

Responses

Request samples

Content type
application/json

CreateViennaNorthArea

{
  • "name": "Vienna North",
  • "description": "Alpine Facility Services coverage north of the Danube",
  • "color": "#1570EF",
  • "geo_json": {
    },
  • "zip_ranges": [
    ]
}

Response samples

Content type
application/json

CreatedViennaNorthArea

{
  • "id": "00000000-0000-4000-8000-000000002001",
  • "name": "Vienna North",
  • "description": "Alpine Facility Services coverage north of the Danube",
  • "color": "#1570EF",
  • "geo_json": {
    },
  • "zip_ranges": [
    ],
  • "created_at": "2026-08-20T08:30:00Z",
  • "updated_at": "2026-08-20T08:30:00Z",
  • "lock_version": 0
}

Get an area

Requires the 'areas:read' grant.

Authorizations:
BearerAuth
path Parameters
area_id
required
string <uuid>

UUID of the area.

Responses

Response samples

Content type
application/json

ViennaNorthArea

{
  • "id": "00000000-0000-4000-8000-000000002001",
  • "name": "Vienna North",
  • "description": "Alpine Facility Services coverage north of the Danube",
  • "color": "#1570EF",
  • "geo_json": {
    },
  • "zip_ranges": [
    ],
  • "created_at": "2026-08-20T08:30:00Z",
  • "updated_at": "2026-08-20T08:30:00Z",
  • "lock_version": 0
}

Delete an area

Requires the 'areas:delete' grant.

Authorizations:
BearerAuth
path Parameters
area_id
required
string <uuid>

UUID of the area.

Responses

Response samples

Content type
application/problem+json
{
  • "title": "Validation failed",
  • "status": 422,
  • "detail": "One or more fields failed validation",
  • "instance": "string",
  • "errors": [
    ],
  • "data": {
    }
}

Update an area

JSON Merge Patch (RFC 7386): omitted fields remain unchanged; a field set to null is cleared (description and color). Requires the 'areas:update' grant.

Authorizations:
BearerAuth
path Parameters
area_id
required
string <uuid>

UUID of the area.

Request Body schema: application/merge-patch+json
required
name
string

Display name of the area. Omitted leaves the value unchanged. Explicit null is rejected (422) — name is required and cannot be cleared.

description
string or null

Optional description. Omitted leaves the value unchanged; explicit null clears it.

color
string or null

Hex color used to render the area overlay on maps. Omitted leaves the value unchanged; explicit null clears it.

geo_json
any

GeoJSON Feature / FeatureCollection containing exactly one Polygon or MultiPolygon. Omitted or null leaves the value unchanged.

Array of objects or null (ZipRange)

Optional postal-code ranges that fall inside this area. Omitted or null leaves the value unchanged; a provided list replaces the stored ranges.

lock_version
integer or null <int64>

Optimistic lock version returned by the previous read

Responses

Request samples

Content type
application/merge-patch+json
Example

RenameViennaNorthArea

{
  • "name": "Vienna North Operations",
  • "lock_version": 0
}

Response samples

Content type
application/json

UpdatedViennaNorthArea

{
  • "id": "00000000-0000-4000-8000-000000002001",
  • "name": "Vienna North Operations",
  • "description": "Alpine Facility Services coverage north of the Danube",
  • "color": "#1570EF",
  • "geo_json": {
    },
  • "zip_ranges": [
    ],
  • "created_at": "2026-08-20T08:30:00Z",
  • "updated_at": "2026-08-20T09:30:00Z",
  • "lock_version": 1
}

Brands

Brands management API

List brands

Returns a paginated list of brands.

Authorizations:
BearerAuth
query Parameters
page
integer >= 0
Default: 0

Page number (0-based).

size
integer [ 1 .. 100 ]
Default: 20

Number of items per page (max 100).

sort
Array of strings
Example: sort=name:asc

Repeated sorting criteria in field:direction format. Allowed fields: id, name, email, phone_number, created_at, updated_at. Default: created_at:desc.

search
string

Search term for brand name, email, or phone number.

Responses

Response samples

Content type
application/json

BrandsListResponse

{}

Create a brand

Creates a brand. Logo updates should use the presigned upload intent endpoints under /api/v2/brands/{brand_id}/logo/uploads.

Authorizations:
BearerAuth
Request Body schema: application/json
required
name
required
string [ 0 .. 255 ] characters

Brand name

email
string <email> [ 0 .. 255 ] characters

Brand contact email

phone_number
string [ 0 .. 255 ] characters

International contact number. An explicit '+' country code is required; common formatting is accepted and normalized to canonical E.164. National numbers are rejected.

theme_id
string <uuid>

Optional custom theme linked to this brand

Responses

Request samples

Content type
application/json

CreateBrandRequest

{
  • "name": "Alpine Facility Services GmbH",
  • "email": "dispatch@example.invalid",
  • "phone_number": "+43 1 234 56 789"
}

Response samples

Content type
application/json

CreateBrandResponse

{}

Create brand logo upload intent

Creates a presigned upload URL for brand logo uploads (PNG/JPEG only).

Authorizations:
BearerAuth
path Parameters
brand_id
required
string <uuid>

UUID of the brand.

Request Body schema: application/json
required
original_file_name
required
string non-empty

Original filename for the brand logo upload.

mime_type
required
string non-empty (?i)^image/(png|jpe?g)$

MIME type of the brand logo upload (image/png or image/jpeg).

Responses

Request samples

Content type
application/json

CreateBrandLogoUpload

{
  • "original_file_name": "alpine-brand-logo.png",
  • "mime_type": "image/png"
}

Response samples

Content type
application/json

AlpineBrandLogoUpload

{
  • "file_id": "00000000-0000-4000-8000-000000000811",
  • "upload_fields": {
    },
  • "upload_url_expires_at": "2026-08-20T10:20:00Z"
}

Create brand favicon upload intent

Creates a presigned upload URL for brand favicon uploads (PNG only).

Authorizations:
BearerAuth
path Parameters
brand_id
required
string <uuid>

UUID of the brand.

Request Body schema: application/json
required
original_file_name
required
string non-empty

Original filename for the brand favicon upload.

mime_type
required
string non-empty (?i)^image/png$

MIME type of the brand favicon upload (image/png only).

Responses

Request samples

Content type
application/json

CreateBrandFaviconUpload

{
  • "original_file_name": "alpine-brand-favicon.png",
  • "mime_type": "image/png"
}

Response samples

Content type
application/json

AlpineBrandFaviconUpload

{}

Link a verified custom domain to this brand

Idempotent: re-linking the same pair is a no-op. Returns 422 if the domain is not in VERIFIED status, or if it is already linked to a different brand.

Authorizations:
BearerAuth
path Parameters
brand_id
required
string <uuid>

UUID of the brand.

custom_domain_id
required
string <uuid>

UUID of the custom-domain link.

Responses

Response samples

Content type
application/problem+json
{
  • "title": "Validation failed",
  • "status": 422,
  • "detail": "One or more fields failed validation",
  • "instance": "string",
  • "errors": [
    ],
  • "data": {
    }
}

Remove the link between this brand and a custom domain

Idempotent: unlinking a pair that is not linked returns 204. The custom domain row itself is untouched.

Authorizations:
BearerAuth
path Parameters
brand_id
required
string <uuid>

UUID of the brand.

custom_domain_id
required
string <uuid>

UUID of the custom-domain link.

Responses

Response samples

Content type
application/problem+json
{
  • "title": "Validation failed",
  • "status": 422,
  • "detail": "One or more fields failed validation",
  • "instance": "string",
  • "errors": [
    ],
  • "data": {
    }
}

Get brand by ID

Returns one brand by its UUID.

Authorizations:
BearerAuth
path Parameters
brand_id
required
string <uuid>

UUID of the brand.

Responses

Response samples

Content type
application/json

BrandResponse

{}

Delete a brand

Permanently removes the brand and its linked branding assets.

Authorizations:
BearerAuth
path Parameters
brand_id
required
string <uuid>

UUID of the brand.

Responses

Response samples

Content type
application/problem+json
{
  • "title": "Validation failed",
  • "status": 422,
  • "detail": "One or more fields failed validation",
  • "instance": "string",
  • "errors": [
    ],
  • "data": {
    }
}

Update a brand

JSON Merge Patch (RFC 7386). Fields omitted remain unchanged; fields set to null are cleared (for nullable fields).

Authorizations:
BearerAuth
path Parameters
brand_id
required
string <uuid>

UUID of the brand.

Request Body schema: application/merge-patch+json
required
lock_version
integer or null <int64>

Optimistic-locking version: validated when provided (409 on mismatch); omitting it skips the concurrency check

name
string

Brand name. Omitted leaves the value unchanged. Explicit null is rejected (422) — name is required and cannot be cleared.

email
string or null

Brand contact email. Omitted leaves the value unchanged; explicit null clears it.

phone_number
string or null

International contact number. An explicit '+' country code is required; common formatting is accepted and normalized to canonical E.164. National numbers are rejected. Omitted leaves the value unchanged; explicit null clears it.

theme_id
string or null <uuid>

Optional custom theme linked to this brand. Omitted leaves the value unchanged; explicit null clears it.

Responses

Request samples

Content type
application/merge-patch+json

UpdateBrandNull

{
  • "lock_version": 2,
  • "email": null,
  • "phone_number": "+43 1 234 56 789"
}

Response samples

Content type
application/json

BrandResponse

{}

Get brand logo upload status

Returns upload lifecycle status for a brand logo upload session.

Authorizations:
BearerAuth
path Parameters
brand_id
required
string <uuid>

UUID of the brand.

file_id
required
string <uuid>

UUID of the uploaded file.

Responses

Response samples

Content type
application/json

UploadedAlpineBrandLogo

{}

Get brand favicon metadata

Returns the public proxy URL for the current brand favicon.

Authorizations:
BearerAuth
path Parameters
brand_id
required
string <uuid>

UUID of the brand.

Responses

Response samples

Content type
application/json

AlpineBrandFavicon

Delete brand favicon

Removes the current brand favicon.

Authorizations:
BearerAuth
path Parameters
brand_id
required
string <uuid>

UUID of the brand.

Responses

Response samples

Content type
application/problem+json
{
  • "title": "Validation failed",
  • "status": 422,
  • "detail": "One or more fields failed validation",
  • "instance": "string",
  • "errors": [
    ],
  • "data": {
    }
}

Get brand favicon upload status

Returns upload lifecycle status for a brand favicon upload session.

Authorizations:
BearerAuth
path Parameters
brand_id
required
string <uuid>

UUID of the brand.

file_id
required
string <uuid>

UUID of the uploaded file.

Responses

Response samples

Content type
application/json

UploadedAlpineBrandFavicon

{}

Geocoding Settings

Geocoding settings API

Get geocoding settings

Returns the default country and default focus point used by geocoding flows.

Authorizations:
BearerAuth

Responses

Response samples

Content type
application/json

ViennaGeocodingSettings

{
  • "default_country": "AT",
  • "default_focus_point": {
    },
  • "map": {
    }
}

Update geocoding settings

JSON Merge Patch (RFC 7386). Omitted fields remain unchanged; null resets a field to the default value. Inside map, omitted sub-fields also remain unchanged, so a patch may name a single zoom level. The whole patch is applied atomically: if any field fails validation, none is stored.

Authorizations:
BearerAuth
Request Body schema: application/merge-patch+json
required
default_country
string or null

Default country as ISO 3166-1 alpha-2 code. Omit to leave unchanged; null resets to the default (DE).

GeocodingFocusPoint (object) or null

Default focus point used to bias forward geocoding results. Omit to leave unchanged; null resets to the default (Berlin).

UpdateGeocodingMapDefaults (object) or null

Map defaults. Omit to leave unchanged; include only the sub-fields you want to change; null resets the whole block to the defaults (zoom 11, overview zoom 5.5, STREETS).

Responses

Request samples

Content type
application/merge-patch+json
Example

UpdateDefaultCountryOnly

{
  • "default_country": "AT"
}

Response samples

Content type
application/json

UpdatedViennaGeocodingSettings

{
  • "default_country": "AT",
  • "default_focus_point": {
    },
  • "map": {
    }
}

Roles

Role listing API.

List roles

Returns roles the current user can assign, plus their own roles, with enabled grants.

Authorizations:
BearerAuth
query Parameters
search
string
Example: search=dispatcher

Case-insensitive partial match on role name.

page
integer >= 0
Default: 0

Page number (0-based).

size
integer [ 1 .. 100 ]
Default: 20
Example: size=20

Number of items per page (max 100).

Responses

Response samples

Content type
application/json

RolesResponse

{
  • "items": [
    ],
  • "page": {
    }
}

Create a role

Creates a role with the provided grants. Grants the caller does not have are ignored.

Authorizations:
BearerAuth
Request Body schema: application/json
required
name
required
string non-empty

Role name

grants
required
Array of strings unique

List of grants enabled for this role

assignable_by_roles
required
Array of strings <uuid> non-empty unique [ items <uuid > ]

Role IDs that are allowed to assign this role

description
string

Optional role description

Responses

Request samples

Content type
application/json

CreateTechnicianRole

{
  • "name": "technician",
  • "grants": [
    ],
  • "assignable_by_roles": [
    ],
  • "description": "Field technicians who maintain customer equipment."
}

Response samples

Content type
application/json

CreateRoleResponse

{
  • "id": "00000000-0000-4000-8000-000000001101",
  • "name": "technician",
  • "description": "Field technicians who maintain customer equipment.",
  • "grants": [
    ],
  • "assignable_by_roles": [
    ],
  • "member_count": 1,
  • "can_assign": true,
  • "editable": true,
  • "is_system_role": false,
  • "lock_version": 0
}

Get a role

Returns a single role by its unique identifier.

Authorizations:
BearerAuth
path Parameters
role_id
required
string <uuid>
Example: 4b3c2d1e-9a8b-4c6d-8e0f-1234567890ab

UUID of the role to retrieve

Responses

Response samples

Content type
application/json

RoleResponse

{
  • "id": "00000000-0000-4000-8000-000000001101",
  • "name": "technician",
  • "description": "Field technicians who maintain customer equipment.",
  • "grants": [
    ],
  • "assignable_by_roles": [
    ],
  • "member_count": 1,
  • "can_assign": true,
  • "editable": true,
  • "is_system_role": false,
  • "lock_version": 0
}

Delete a role

Deletes a role by its unique identifier.

Authorizations:
BearerAuth
path Parameters
role_id
required
string <uuid>

UUID of the role.

Responses

Response samples

Content type
application/problem+json
{
  • "title": "Validation failed",
  • "status": 422,
  • "detail": "One or more fields failed validation",
  • "instance": "string",
  • "errors": [
    ],
  • "data": {
    }
}

Update a role

JSON Merge Patch (RFC 7386): omitted fields remain unchanged; a field set to null is cleared (description). Grants the caller does not have are ignored.

Authorizations:
BearerAuth
path Parameters
role_id
required
string <uuid>

UUID of the role.

Request Body schema: application/merge-patch+json
required
lock_version
integer or null <int64>

Optimistic-locking version: validated when provided (409 on mismatch); omitting it skips the concurrency check

name
string

Role name. Omitted leaves the value unchanged. Explicit null is rejected (422) — name is required and cannot be cleared.

grants
Array of strings unique

List of grants enabled for this role; replaces the full grant set when provided. Omitted leaves the value unchanged. Explicit null is rejected (422).

assignable_by_roles
Array of strings <uuid> unique [ items <uuid > ]

Role IDs that are allowed to assign this role; replaces the full set when provided. Omitted leaves the value unchanged. Explicit null is rejected (422).

description
string or null

Optional role description. Omitted leaves the value unchanged; explicit null clears it.

Responses

Request samples

Content type
application/merge-patch+json

UpdateRoleNull

{
  • "name": "technician",
  • "description": null
}

Response samples

Content type
application/json

UpdateRoleResponse

{
  • "id": "00000000-0000-4000-8000-000000001101",
  • "name": "technician",
  • "description": "Field technicians who maintain customer equipment.",
  • "grants": [
    ],
  • "assignable_by_roles": [
    ],
  • "member_count": 1,
  • "can_assign": true,
  • "editable": true,
  • "is_system_role": false,
  • "lock_version": 0
}

Webhooks

Tag: tag.created Webhook

Delivered when this happens to a tag.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "tag.created"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "tag.created",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

Tag: tag.updated Webhook

Delivered when this happens to a tag.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "tag.updated"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "tag.updated",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

Tag: tag.deleted Webhook

Delivered when this happens to a tag.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "tag.deleted"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "tag.deleted",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

SMS gateway: sms_gateway.created Webhook

Delivered when this happens to a sms gateway.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "sms_gateway.created"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "sms_gateway.created",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

SMS gateway: sms_gateway.updated Webhook

Delivered when this happens to a sms gateway.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "sms_gateway.updated"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "sms_gateway.updated",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

SMS gateway: sms_gateway.deleted Webhook

Delivered when this happens to a sms gateway.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "sms_gateway.deleted"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "sms_gateway.deleted",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

Brand: brand.created Webhook

Delivered when this happens to a brand.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "brand.created"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "brand.created",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

Brand: brand.updated Webhook

Delivered when this happens to a brand.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "brand.updated"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "brand.updated",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

Brand: brand.deleted Webhook

Delivered when this happens to a brand.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "brand.deleted"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "brand.deleted",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

Skill: skill.created Webhook

Delivered when this happens to a skill.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "skill.created"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "skill.created",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

Skill: skill.updated Webhook

Delivered when this happens to a skill.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "skill.updated"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "skill.updated",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

Skill: skill.deleted Webhook

Delivered when this happens to a skill.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "skill.deleted"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "skill.deleted",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

Area: area.created Webhook

Delivered when this happens to a area.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "area.created"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "area.created",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

Area: area.updated Webhook

Delivered when this happens to a area.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "area.updated"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "area.updated",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

Area: area.deleted Webhook

Delivered when this happens to a area.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "area.deleted"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "area.deleted",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

Measure unit: measure_unit.created Webhook

Delivered when this happens to a measure unit.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "measure_unit.created"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "measure_unit.created",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

Measure unit: measure_unit.updated Webhook

Delivered when this happens to a measure unit.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "measure_unit.updated"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "measure_unit.updated",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

Measure unit: measure_unit.deleted Webhook

Delivered when this happens to a measure unit.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "measure_unit.deleted"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "measure_unit.deleted",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

Role: role.updated Webhook

Delivered when this happens to a role.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "role.updated"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "role.updated",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

User: user.created Webhook

Delivered when this happens to a user.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "user.created"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "user.created",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

User: user.updated Webhook

Delivered when this happens to a user.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "user.updated"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "user.updated",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

User: user.deleted Webhook

Delivered when this happens to a user.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "user.deleted"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "user.deleted",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

Theme: theme.created Webhook

Delivered when this happens to a theme.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "theme.created"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "theme.created",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

Theme: theme.updated Webhook

Delivered when this happens to a theme.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "theme.updated"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "theme.updated",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

Theme: theme.deleted Webhook

Delivered when this happens to a theme.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "theme.deleted"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "theme.deleted",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

File: file.created Webhook

Delivered when this happens to a file.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "file.created"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "file.created",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

File: file.updated Webhook

Delivered when this happens to a file.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "file.updated"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "file.updated",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

File: file.deleted Webhook

Delivered when this happens to a file.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "file.deleted"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "file.deleted",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

Document: document.created Webhook

Delivered when this happens to a document.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "document.created"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "document.created",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

Document: document.updated Webhook

Delivered when this happens to a document.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "document.updated"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "document.updated",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

Document: document.deleted Webhook

Delivered when this happens to a document.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "document.deleted"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "document.deleted",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

Document version: document.version.created Webhook

Delivered when this happens to a document version.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "document.version.created"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "document.version.created",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

Document permissions: document.permissions.updated Webhook

Delivered when this happens to a document permissions.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "document.permissions.updated"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "document.permissions.updated",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

Folder: folder.created Webhook

Delivered when this happens to a folder.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "folder.created"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "folder.created",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

Folder: folder.updated Webhook

Delivered when this happens to a folder.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "folder.updated"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "folder.updated",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

Folder: folder.deleted Webhook

Delivered when this happens to a folder.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "folder.deleted"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "folder.deleted",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

Folder permissions: folder.permissions.updated Webhook

Delivered when this happens to a folder permissions.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "folder.permissions.updated"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "folder.permissions.updated",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

Comment: comment.created Webhook

Delivered when this happens to a comment.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "comment.created"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "comment.created",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

Comment: comment.updated Webhook

Delivered when this happens to a comment.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "comment.updated"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "comment.updated",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

Comment reaction: comment.reaction.created Webhook

Delivered when this happens to a comment reaction.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "comment.reaction.created"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "comment.reaction.created",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

Comment reaction: comment.reaction.deleted Webhook

Delivered when this happens to a comment reaction.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "comment.reaction.deleted"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "comment.reaction.deleted",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

Custom object: custom_object.example.created Webhook

Illustrative custom-object delivery. example stands for the definition's actual slug.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "custom_object.example.created"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "custom_object.example.created",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

Custom object: custom_object.example.updated Webhook

Illustrative custom-object delivery. example stands for the definition's actual slug.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "custom_object.example.updated"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "custom_object.example.updated",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

Custom object: custom_object.example.deleted Webhook

Illustrative custom-object delivery. example stands for the definition's actual slug.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "custom_object.example.deleted"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "custom_object.example.deleted",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

Custom object permissions: custom_object.example.permissions.updated Webhook

Illustrative custom-object delivery. example stands for the definition's actual slug.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "custom_object.example.permissions.updated"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "custom_object.example.permissions.updated",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

Custom object definition: custom_object_definition.created Webhook

Delivered when this happens to a custom object definition.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "custom_object_definition.created"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "custom_object_definition.created",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

Custom object definition: custom_object_definition.updated Webhook

Delivered when this happens to a custom object definition.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "custom_object_definition.updated"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "custom_object_definition.updated",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

Custom object definition: custom_object_definition.deleted Webhook

Delivered when this happens to a custom object definition.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "custom_object_definition.deleted"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "custom_object_definition.deleted",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

Device: device.created Webhook

Delivered when this happens to a device.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "device.created"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "device.created",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

Device: device.updated Webhook

Delivered when this happens to a device.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "device.updated"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "device.updated",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

Device: device.deleted Webhook

Delivered when this happens to a device.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "device.deleted"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "device.deleted",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

Vehicle: vehicle.created Webhook

Delivered when this happens to a vehicle.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "vehicle.created"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "vehicle.created",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}

Vehicle: vehicle.updated Webhook

Delivered when this happens to a vehicle.

Authorizations:
BearerAuth
header Parameters
webhook-id
required
string <uuid>

Unique message id (UUID). Stable across retries of the same event — use it as an idempotency key.

webhook-timestamp
required
string^[0-9]+$
Example: 1787565600

Unix timestamp in seconds at which this delivery attempt was signed. Reject deliveries outside your tolerance window.

webhook-signature
required
string
Example: v1,dGVzdC1zaWduYXR1cmU=

Standard Webhooks signature: v1, + base64 HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw_body}.

Request Body schema: application/json
required
type
required
string

Event name: <resource path>.<verb>, e.g. folder.updated or folder.permissions.updated.

Value: "vehicle.updated"
id
required
string <uuid>

Delivery id, identical to the webhook-id header. Unique per endpoint and stable across retries — use it as this endpoint's idempotency key.

event_id
required
string <uuid>

Id of the underlying event. Identical across every endpoint and every retry that delivers it — use it to deduplicate when more than one endpoint feeds one consumer.

timestamp
required
string <date-time>

When the event occurred (ISO 8601, UTC). Not the time this attempt was signed — that is the webhook-timestamp header, and the two differ on a retry.

payload_version
required
integer <int32>

Version of the payload shape this endpoint is pinned to. Independent of the version of the API used to register the endpoint.

Value: 1
tenant_id
required
string <uuid>

Workspace the event belongs to.

object (WebhookActor)

The principal that caused the event.

object (WebhookRequestContext)

Tracing handles for the API request that caused this event.

required
object

The resource this event is about, plus the previous values of any changed fields.

Responses

Request samples

Content type
application/json
{
  • "type": "vehicle.updated",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
  • "timestamp": "2026-08-24T10:00:00Z",
  • "payload_version": 1,
  • "tenant_id": "34f5c98e-f430-457b-a812-92637d0c6fd0",
  • "actor": {
    },
  • "request": {
    },
  • "data": {
    }
}