Skip to content

API reference ​

What a product's client calls: an anonymous identity the service makes, reports and their answers (live), a contact only if the user gives one, moving the identity to another device, and the user's own data. Every request carries the product's key (X-Alias-Key); all but three carry the user too (X-Alias-User, X-Alias-Secret, as POST /api/v1/identity or a transfer gave them).

Errors are {"error": "…"} with a status: 400 (what's wrong, in words), 401 (no such key, id or secret), 403 (blocked, or a browser origin the product doesn't allow), 404, 409, 413, 429 (a limit: try later), 5xx. The clients follow this description: the same calls and names in each.

The spec: OpenAPI 3.1.0, openapi.yaml or openapi.json, for code generators, Postman, Insomnia and the like.

Headers. Every request carries the product's key, X-Alias-Key. Calls marked user also carry the user's X-Alias-User and X-Alias-Secret.

Operations ​

getProduct ​

GET /api/v1/product · key only

The product's public settings (for the client's UI).

Answers:

newIdentity ​

POST /api/v1/identity · key only

A new anonymous identity, made by the service (or a new secret for an id support reset).

Limited to 20 an hour per address per product, and by a budget per key. If the product asks for proof of work (identityChallenge says how many bits), the request carries X-Alias-Work: <challenge>:<nonce>, where SHA-256 of that whole value begins with that many zero bits. Without it, or with a challenge out of time or used: 428 (ask for another challenge).

ParameterInType
X-Alias-Workheaderstring<challenge>:<nonce>, when the product asks for proof of work.

Body (optional): object

FieldType
id (optional)stringAn id whose secrets support reset.

Answers:

identityChallenge ​

GET /api/v1/identity/challenge · key only

The proof of work a new identity costs, if any (a challenge good for five minutes, once).

bits 0: none, post the identity as it is. Otherwise find a nonce such that SHA-256 of <challenge>:<nonce> begins with bits zero bits (about 2^bits tries), and send that as X-Alias-Work. The bits can go up at any time (an attack, a key in quarantine), so a client always asks.

Answers:

  • 200 The work asked for: object
    • bits: integer
    • challenge: string
    • expires_at: string (date-time)
  • otherwise an Error

claimTransfer ​

POST /api/v1/transfer/claim · key only

This device gets the identity a transfer code names, with a secret of its own.

10 tries an hour per address per product; a code ends after 5 wrong tries, or 10 minutes.

Body: object

FieldType
codestring

Answers:

me ​

GET /api/v1/me · user

The id and secret are good; the id's devices and contact.

Answers:

eraseMe ​

DELETE /api/v1/me · user

Erase the id and everything of it (reports, attachments, contact), for good.

Answers:

  • 200 Erased: object
    • erased: string
    • tickets: integer
  • otherwise an Error

myData ​

GET /api/v1/me/data · user

A copy of everything kept about the id, as JSON (attachments base64).

Answers:

  • 200 The copy: object
  • otherwise an Error

getContact ​

GET /api/v1/me/contact · user

The contact given (null none), and the product's policy.

Answers:

setContact ​

PUT /api/v1/me/contact · user

Give (or change) a contact, with the user's consent, if the product takes one (else 409).

Only after the user agreed to the product's contact_consent text, shown whole: consent.version is that text's version. Without it 400; with an older text's 409 (show the current one and ask again). The consent is recorded with the text; a new contact ends the one before (replaced).

Body: object

FieldType
kindemail, other
valuestringup to 254 characters
consentobject

Answers:

withdrawContact ​

DELETE /api/v1/me/contact · user

Withdraw the contact (deleted at once; its consent's record kept, ended, until the identity goes).

Answers:

newTransfer ​

POST /api/v1/me/transfer · user

A code to type on another device within 10 minutes.

Answers:

tickets ​

GET /api/v1/tickets · user

The user's tickets, newest first (50), without their threads.

Answers:

  • 200 The list: object
  • otherwise an Error

report ​

POST /api/v1/tickets · user

Send a report.

JSON, or multipart/form-data with files (the product's attachments limits and types).

Body: Report

Answers:

ticket ​

GET /api/v1/tickets/{id} · user

One ticket, with its thread.

ParameterInType
idpathinteger (int64)

Answers:

reply ​

POST /api/v1/tickets/{id}/comments · user

Reply (a ticket waiting on the user, or resolved, opens again; a closed one is 409).

ParameterInType
idpathinteger (int64)

Body: Reply

Answers:

requestLive ​

POST /api/v1/tickets/{id}/live · user

Ask to talk about the ticket live.

If someone at the desk is taking live conversations, the ticket goes live at once (mode live); otherwise it's marked (live_requested_at) and goes live when support takes it. 403 when the product doesn't let users ask (live.user_may_ask).

ParameterInType
idpathinteger (int64)

Answers:

typing ​

POST /api/v1/tickets/{id}/typing · user

The user is typing (a live ticket's; at most one every 2 s is passed on).

ParameterInType
idpathinteger (int64)

Answers:

  • 204 Noted
  • otherwise an Error

markRead ​

POST /api/v1/tickets/{id}/read · user

The user has read the thread up to now (support sees it).

ParameterInType
idpathinteger (int64)

Answers:

  • 204 Noted
  • otherwise an Error

attachment ​

GET /api/v1/tickets/{id}/attachments/{aid} · user

One of the user's own attachments, as kept.

ParameterInType
idpathinteger (int64)
aidpathinteger (int64)

Answers:

  • 200 The file
  • otherwise an Error

remoteRequests ​

GET /api/v1/remote · user

The user's remote assistance requests still going, across their tickets.

What a device's agent watches (with the remote events): support asked to open a shell (SSH) or see the screen (VNC) on this device. Nothing connects until the device accepts. offered: the product offers remote assistance at all on this deployment.

Answers:

ticketRemote ​

GET /api/v1/tickets/{id}/remote · user

A ticket's remote assistance requests, all of them, newest first.

ParameterInType
idpathinteger (int64)

Answers:

answerRemote ​

POST /api/v1/tickets/{id}/remote/{rid} · user

The device's answer to a request.

Yes: the relay's session is made and relay is this device's side of it: dial url (a WebSocket) with token as the bearer and connect it to what the channel is on this device (the device's own setting: 127.0.0.1:22 for shell, :5900 for screen), never anything support names. The session is single attach: when either side leaves it's over. Asking yes again before anyone's on it gives the same again. 409: it's not waiting for an answer any more.

ParameterInType
idpathinteger (int64)
ridpathstring

Body: object

FieldType
acceptboolean

Answers:

endRemote ​

DELETE /api/v1/tickets/{id}/remote/{rid} · user

The device ends the session (or takes its yes back).

ParameterInType
idpathinteger (int64)
ridpathstring

Answers:

  • 200 Ended
  • otherwise an Error

updates ​

GET /api/v1/updates · user

The tickets support answered or changed since a time (polling).

now is the time to ask from next, by the service's clock and a moment early, so an update can come twice (by poll and stream, or two polls): drop what's been seen, by ticket and at.

ParameterInType
sincequerystring (date-time)The last answer's now; none: everything support ever touched.

Answers:

  • 200 Updates, and the time to ask from next: object
    • updates: array of Update
    • now: string (date-time)
  • otherwise an Error

events ​

GET /api/v1/events · user

The same, pushed (Server-Sent Events) while open.

An Update as data, its kind the event: answer; on a live ticket also mode (it went live or back), typing (support is typing) and read (support read up to at); remote when a remote assistance request is asked or changes. A comment line every 25 s. At most 3 streams per user. A client that can't send headers on a stream (a browser's EventSource) polls /api/v1/updates instead.

Answers:

  • 200 The stream: string
  • otherwise an Error

Objects ​

Error ​

FieldType
errorstring
code (optional)key_revokedWhat kind of refusal, when it's one a client acts on. key_revoked: this build's key was revoked.
reason (optional)stringkey_revoked: support's words for the user ("This version is no longer supported"), when they gave some. Show it as it is.; up to 300 characters

RemoteRequest ​

FieldType
idstring
ticketinteger (int64)
channelshell, screenshell: SSH to the device's sshd (its own sign-in still applies). screen: VNC; not encrypted end to end, the relay's operator could see it.
stateasked, accepted, open, ended, declined, expired
asked_bystringThe support person's name.
asked_atstring (date-time)
deadlinestring (date-time)asked: answer by; accepted, open: the session's end.
end_reason (optional)stringleft, ended_by_support, ended_by_user, time_up, nobody_came, relay, not answered.
relay (optional)objectThe device's side, once accepted (answerRemote's answer only).

Identity ​

FieldType
idstringA UUID v7.; e.g. 01a1a2b3-9cdf-71e1-b2d5-91d78e28a35a
secretstringShown this once: keep it (only its hash is kept here).; pattern ^[0-9a-f]{64}$

Field ​

FieldType
namestring
label (optional)string
typetext, number, bool, geo, link, json
template (optional)stringA link's: {field} replaced by that field's value.

Product ​

FieldType
idstring
namestring
privacy_url (optional)string
branding (optional)object
fieldsarray of FieldWhat a report's context may carry; the rest is dropped.
contactoff, optional
contact_consent (optional)ConsentText or nullWith contact optional: the text to show by the contact field.
contact_kindsarray of email, other
keepingobject
redact (optional)array of RedactRuleApplied, in order, to what the user sends, before it leaves the device; the service applies them again as it comes in. Skip a rule that's server_only (hash) or a strategy the client doesn't know; a client:<name> strategy is the app's own.
removable (optional)array of stringPaths (as a rule's) the user may take out before sending: show the telemetry, offer these.
attachments (optional)AttachmentLimits
formats (optional)array of Format
telemetry_max (optional)integerThe telemetry's bytes at most, as JSON.
conversations (optional)objectHow the product's tickets run.
live (optional)objectLive now, as the client should offer it.

RedactRule ​

FieldType
pathstring/telemetry/… (a JSON pointer, * for every key or element), /context/<field>, or /note (a note and a reply's text).; e.g. /telemetry/peers/*/ip
strategystringdrop, mask, truncate, round, coarsen, regex, hash (server only), or client:<name>.
server_onlyboolean
keep (optional)integermask: ••••, then the last keep characters (leading • aren't counted).
max (optional)integertruncate: the characters kept.
step (optional)numberround: to the nearest multiple.
digits (optional)integercoarsen: a number, or a geo value's lat and lon, to these decimals.
pattern (optional)stringregex: RE2, in every text under the path.
replace (optional)stringregex: what a match becomes, literally ([redacted]).

AttachmentLimits ​

FieldType
maxintegerFiles a report or a reply may carry.
bytesintegerTheir bytes together.
typesarray of image/jpeg, image/png, image/webp, text/plain, application/jsonTold from the bytes, not the name or the part's type.

Attachment ​

FieldType
idinteger (int64)
namestringLetters, digits, . - _; unique in its report or reply: what names.
typestring
sizeinteger
created_atstring (date-time)

Format ​

text/markdown: CommonMark with GFM's tables, strikethrough and autolinks; no raw HTML, and no images but the report's own attachments (![](attachment:name)). Render it, or show it as it is.

text/plain, text/markdown

Me ​

FieldType
idstring
created_atstring (date-time)
devicesintegerDevices holding a secret for this id.
contact (optional)Contact or null

Contact ​

FieldType
kindemail, other
valuestring
given_atstring (date-time)
consent (optional)Consent

ConsentText ​

FieldType
textstringShow it, whole, where the user gives a contact; send nothing until they agree to it.
versionstringThe text's hash: send it back with the contact, as proof of which text was shown.

What the user agreed to in giving a contact, as recorded. Kept, ended or not, until the identity goes.

FieldType
idinteger (int64)
purposecontact
versionstring
textstringThe text as it was when they agreed.
kindemail, other
app_version (optional)string
given_atstring (date-time)
ended_at (optional)string (date-time)
ended (optional)withdrawn, replaced

ContactState ​

FieldType
contactContact or null
policy (optional)off, optional
kinds (optional)array of string
consent (optional)ConsentText or nullThe text to show now (as the product's contact_consent).

Report ​

FieldType
notestringup to 4000 characters
format (optional)Format
screenshot (optional)stringA JPEG, up to 3 MB (JSON only: as multipart, send it as an attachment).
context (optional)objectThe product's fields (GET /api/v1/product).
app_version (optional)stringup to 40 characters
telemetry (optional)objectFree JSON up to the product's size, matching its schema if it has one (else 400, saying where).

Reply ​

FieldType
bodystringup to 4000 characters
format (optional)Format
screenshot (optional)string
context (optional)object
telemetry (optional)object

Entry ​

FieldType
idinteger (int64)
authoruser, support
name (optional)stringA support person's name.
agent (optional)booleanSupport's, but written by an agent (a service account: an AI agent, a script), not a person. Show the user it was.
kindcomment, status, modestatus: body is the new status; mode: the ticket's new mode.
bodystring
format (optional)Format
created_atstring (date-time)
context (optional)object
attachments (optional)array of Attachment
has_screenshot (optional)booleanAn image among the attachments.

Status ​

open, in_progress, waiting, resolved, closed

Mode ​

tickets: request and response; live: a conversation, as it happens.

tickets, live

Ticket ​

FieldType
idinteger (int64)
productstring
statusStatus
notestring
formatFormat
context (optional)object
app_versionstring
attachmentsarray of AttachmentThe report's own (a reply's are its entry's).
has_screenshotbooleanAn image among the attachments.
created_atstring (date-time)
updated_atstring (date-time)
support_at (optional)string (date-time)Support's last answer or status change.
mode (optional)Mode
live_requested_at (optional)string (date-time)The user asked for live and nobody was there yet.
user_read_at (optional)string (date-time)The user read the thread up to then.
support_read_at (optional)string (date-time)Support read the thread up to then.
thread (optional)array of Entry

Update ​

FieldType
kindanswer, mode, typing, read, remotePolling (updates) has answers only; the stream has all five. remote: a remote assistance request changed (look it up: remoteRequests).
ticketinteger (int64)
statusStatus
atstring (date-time)
mode (optional)Mode
who (optional)supporttyping, read: who.
name (optional)stringtyping: the support person's name.
remote (optional)stringremote: the request's id.
channel (optional)shell, screenremote: which.
state (optional)stringremote: what it is now (RemoteRequest's state).

Transfer ​

FieldType
codestringTyped on the other device (any case; O, I, L read as 0, 1, 1).; pattern ^[0-9A-HJKMNP-TV-Z]{4}-[0-9A-HJKMNP-TV-Z]{4}$
expires_atstring (date-time)

WebhookEvent ​

What a webhook endpoint receives (Standard Webhooks): signed with the webhook-id, webhook-timestamp and webhook-signature headers. The fields marked "content" are there only if the endpoint has content on, and are redacted by the product's rules.

FieldType
typeticket.created, ticket.replied, ticket.answered, ticket.status_changed, ticket.deleted, ticket.live_started, ticket.live_ended, webhook.test
timestampstring (date-time)
dataobject

WebhookTicket ​

FieldType
idinteger (int64)
statusopen, in_progress, waiting, resolved, closed
modetickets, live
app_version (optional)string
created_atstring (date-time)
updated_atstring (date-time)
url (optional)string (uri)the ticket on the panel (with the deployment's public_url)
user (optional)stringcontent: the user's anonymous id
note (optional)stringcontent
format (optional)text/plain, text/markdowncontent
context (optional)objectcontent
telemetry (optional)objectcontent
attachments (optional)array of WebhookFilecontent

WebhookEntry ​

What happened (ticket.replied, .answered, .status_changed, .live_started, .live_ended).

FieldType
idinteger (int64)
authoruser, support
kindcomment, status, mode
created_atstring (date-time)
status (optional)stringkind status: the new status
mode (optional)tickets, livekind mode: the new mode
body (optional)stringcontent
format (optional)stringcontent
name (optional)stringcontent: the support person's name, on an answer
agent (optional)booleanby an agent (a service account), not a person
attachments (optional)array of WebhookFilecontent

WebhookFile ​

FieldType
name (optional)string
type (optional)string
size (optional)integer