For AI agents: markdown of this page — /docs-content-en/cowork/relay-ticket.md documentation index — /llms.txt

Ticket for phone access

POST /v1/cowork/relay-ticket

Issues a signed ticket that the Cowork/Code desktop app uses to connect to the relay, the server through which a phone reaches the desktop. The platform only confirms who is connecting: no traffic passes through it, and the desktop is not registered as a server.

The ticket is valid for 5 minutes and is bound to the desktop public key from the request body: the relay rejects it if presented with any other key. Keep the ticket in memory and reuse it for reconnects while more than 60 seconds remain before expiresAt. Once 60 seconds or less remain before expiresAt, request a new ticket on the next connection.

Scope: vibe:cowork; the key must also be a Cowork/Code desktop key. The key owner must have an active Cowork/Code seat.

Request fields (body)

Field Type Required Description
pubkey string yes The Ed25519 public key the desktop presents to the relay: exactly 32 bytes in base64url without = padding, 43 characters

Examples

This endpoint accepts only a Cowork/Code desktop key, so there are two examples.

curl — Cowork/Code desktop key

Terminal
curl -X POST https://vibecode.bitrix24.com/v1/cowork/relay-ticket \
  -H "X-Api-Key: YOUR_COWORK_KEY" \
  -H "Content-Type: application/json" \
  -d '{"pubkey": "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo"}'

JavaScript — Cowork/Code desktop key

javascript
let cached = null

async function getRelayTicket(pubkey) {
  // Reuse the ticket while more than 60 seconds remain until expiry
  if (cached && Date.parse(cached.expiresAt) - Date.now() > 60_000) {
    return cached.ticket
  }

  const res = await fetch('https://vibecode.bitrix24.com/v1/cowork/relay-ticket', {
    method: 'POST',
    headers: {
      'X-Api-Key': 'YOUR_COWORK_KEY',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ pubkey }),
  })
  if (!res.ok) {
    const { error } = await res.json()
    throw new Error(`${res.status} ${error.code}`)
  }

  cached = await res.json() // { ticket, expiresAt } — no success/data wrapper
  return cached.ticket
}

Response fields

Field Type Description
ticket string A JWS (JSON Web Signature) token in compact serialization, signed with EdDSA. Pass it to the relay as is
expiresAt string When the ticket expires (ISO 8601), 5 minutes after issuance

For reference: the ticket header carries alg: "EdDSA", typ: "JWT" and the kid of the signing key. The payload holds typ: "cowork-relay-ticket", iss: "vibecode-platform", aud: "cowork-relay", sub and portal, cnf.jwk, whose x field holds the pubkey you sent, as well as jti, iat and exp. The sub and portal fields hold pseudonyms: the relay can tell users and Bitrix24 accounts apart by them but does not learn the real identifiers.

Response example

The ticket value is truncated:

JSON
{
  "ticket": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6Ii4uLiJ9.eyJ0eXAiOiJjb3dvcmstcmVsYXktdGlja2V0Ii4uLn0.c2lnbmF0dXJl",
  "expiresAt": "2026-09-22T12:05:00.000Z"
}

Error response example

403 — a key with the vibe:cowork scope that is not a Cowork/Code desktop key:

JSON
{
  "success": false,
  "error": {
    "code": "COWORK_DESKTOP_KEY_REQUIRED",
    "message": "Only a Cowork/Code desktop key may request a relay ticket."
  }
}

Errors

HTTP Code Description
400 INVALID_PUBKEY The pubkey field is missing or is not a 32-byte key in unpadded base64url
400 FST_ERR_CTP_EMPTY_JSON_BODY The Content-Type: application/json header was sent, but the body is empty
400 FST_ERR_CTP_INVALID_JSON_BODY The body cannot be parsed as JSON
401 MISSING_API_KEY The X-Api-Key header is missing
401 INVALID_API_KEY The key is not recognized — no such key exists on the platform
401 KEY_INACTIVE The key has been revoked, for example when the device was signed out with DELETE /v1/cowork/key
401 KEY_EXPIRED The key has expired
402 ACCOUNT_FROZEN The billing account is frozen over a negative balance. This call is not paid for from the balance, so the refusal arrives only while the old freeze rules still apply to your Bitrix24 account. The new rules block only paid calls, and the platform is enabling them gradually
403 INSUFFICIENT_SCOPE The key lacks the vibe:cowork scope
403 COWORK_DESKTOP_KEY_REQUIRED The key does not belong to the Cowork/Code desktop class. This response applies to both agent seat keys and third-party agent keys
403 COWORK_SEAT_INACTIVE The Cowork/Code seat exists, but its state is PAUSED, PARKED or CANCELLED rather than ACTIVE
403 WRITE_BLOCKED_READONLY_KEY The key was issued in read-only mode
404 COWORK_NOT_ACTIVATED The key owner has no Cowork/Code seat on this Bitrix24 account
413 PAYLOAD_TOO_LARGE The body is larger than 4 KB
415 FST_ERR_CTP_INVALID_MEDIA_TYPE The request body uses a content type this route does not parse. Send the body with the Content-Type: application/json header
429 RATE_LIMITED The per-user request limit on the Bitrix24 account has been exceeded; a user's keys share one limit. The platform-wide limit is 30 requests per hour. The effective limit for your key is returned in the x-ratelimit-limit header. It is lower than the platform-wide limit because that limit is divided across replicas
503 COWORK_FEATURE_DISABLED Cowork/Code is disabled at the platform level
503 COWORK_RELAY_NOT_CONFIGURED Ticket issuance is currently unavailable on this platform

Full list of common API errors: Errors.

Known specifics

A successful response (200) is the object itself, with no success wrapper. Errors come in the { success: false, error: { code, message } } envelope. Determine success by the HTTP status (res.ok).

The ticket is not stored on the platform. Each call issues a new ticket, and earlier ones stay valid until their expiresAt. An issued ticket cannot be revoked.

The endpoint checks whether ticket issuance is available before it validates the request body. While ticket issuance is unavailable, the endpoint returns 503 COWORK_RELAY_NOT_CONFIGURED even for a request with an invalid pubkey.

How to react to refusals.

  • 401: ask the user to sign in again.
  • 400, 403 INSUFFICIENT_SCOPE and 403 COWORK_DESKTOP_KEY_REQUIRED: a retry returns the same refusal, so fix the request or the key.
  • 404 COWORK_NOT_ACTIVATED and 403 COWORK_SEAT_INACTIVE: the user needs an active Cowork/Code seat.
  • 503: a platform state, not a problem with the key, so retry later.
  • 429: retry with a growing delay.

See also