Developers

Connect ShareDesk to your tools.

Read the session log with its billing into your invoicing, keep your inventory in step with the address books, and let your ticket system or chat know when a session starts or ends. API keys and webhooks are part of every team account.

Create an API keySee the endpoints

Authentication and API keys

Every request carries an API key: Authorization: Bearer <key>. A team's administrators create keys in the account area under Integrations: a name, one or more scopes and, if you like, an expiry date.

  • Shown once. The key (sdk_live_<id>_<48 hex>) appears only right after you create it. Copy it into your tool's secret store; we keep only a fingerprint and can't show it again. The short <id> part is what the account area lists.
  • Scopes limit what a key may do: sessions:read, computers:read, computers:write, brandings:read. Give each tool only the scopes it needs.
  • Revoking in the account area takes effect at once. Revoked and expired keys, and keys of a disabled team, answer 401.
  • A team can have up to 25 active keys. Creating and revoking keys, and every change made with a key, appear in the team's change log (as “API key «name»”).
Your first request
curl -s "https://api.sharedesk.app/v1/computers?per_page=5" \
  -H "Authorization: Bearer $SHAREDESK_KEY"

Requests and answers are JSON (Content-Type: application/json), over https only.

Rate limits and errors

Each key may make 120 requests per minute (a fixed window per calendar minute). Every answer tells you where you stand:

Rate-limit headers
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 117
X-RateLimit-Reset: 42

Beyond the limit you get 429 with Retry-After (seconds). Errors always have the same shape, with an English message and a stable code to program against:

Error
{"error": "This API key doesn't have the permission \"computers:write\".", "code": "insufficient_scope", "scope": "computers:write"}
Statuscode
400body_invalid, from_invalid, to_invalid, page_invalid, per_page_invalid, sort_invalid, direction_invalid, computer_invalid, owner_invalid, remote_id_invalid, group_invalid, name_invalid, notes_invalid, field_unknown
401key_missing, key_invalid (unknown, revoked or expired; with WWW-Authenticate: Bearer)
403insufficient_scope (with scope: the one missing)
404not_found
405method_not_allowed (with Allow)
409computer_exists
429rate_limited (with Retry-After)
503maintenance, unavailable: try again later

Pagination

Lists take page (from 1) and per_page (1–200, default 50) and answer with the page and the total, so you know when to stop:

A list
{"data": [ … ], "page": 2, "per_page": 50, "total": 137, "has_more": true}

A single item is {"data": { … }}. Keep asking for the next page while has_more is true.

Endpoints

Base address: https://api.sharedesk.app/v1/ (the earlier https://sharedesk.marketvision.ch/api/v1/ keeps working).

GET /sessions sessions:read

The team's session log, newest first: every member's sessions, also of members who have left, with each session's billing exactly as the billing export computes it (rate, billing step and currency of the computer, its groups or the technician, plus any adjustment). Only outgoing, finished sessions are billed; otherwise billing is null. Answers never contain IP addresses.

ParameterMeaning
from, tosessions that started in [from, to): unix seconds or ISO 8601 (2026-10-01, 2026-10-01T08:00:00Z)
computera ShareDesk ID (9 digits) or a computer's id from /computers (then also its earlier IDs)
techniciana member's ID or e-mail address
directionoutgoing (a technician helped someone) or incoming
sort-start (default) or start
page, per_pagesee Pagination
September's sessions
curl -s "https://api.sharedesk.app/v1/sessions?from=2026-09-01&to=2026-10-01&per_page=200" \
  -H "Authorization: Bearer $SHAREDESK_KEY"
Answer of /sessions
{
  "data": [{
    "id": "6F1C…", "direction": "outgoing", "start": 1791380000, "end": 1791381000, "duration_seconds": 1000,
    "technician": {"id": "D05D…", "name": "Anna Muster", "email": "anna@example.ch"},
    "computer": {"remote_id": "987654321", "name": "Empfang-PC", "customer": "Kunde AG", "group": "Kunde AG › Finanzen"},
    "peer": "Empfang", "profile": "Muster IT", "mode": "screen", "access": "", "device": "Annas MacBook Pro",
    "end_reason": "", "note": "", "files_sent": 0, "files_received": 2,
    "billing": {"billable": true, "seconds": 1000, "billed_seconds": 1800, "auto_billed_seconds": 1800,
                "increment_minutes": 15, "rate": 120, "amount": 60, "currency": "CHF", "adjusted": false},
    "updated": 1791381003
  }],
  "page": 1, "per_page": 50, "total": 1, "has_more": false
}

GET /computers computers:read

Every computer in the address books of the team's members, by name. Parameters: q (name or ShareDesk ID), owner (a member's ID or e-mail), group_id, page, per_page. A computer's saved unattended-access key is never part of an answer.

Find a computer
curl -s "https://api.sharedesk.app/v1/computers?q=Empfang" \
  -H "Authorization: Bearer $SHAREDESK_KEY"
Answer of /computers
{
  "data": [{
    "id": "4B0E…", "remote_id": "987654321", "name": "Empfang-PC",
    "group": {"id": "9A1F…", "name": "Finanzen", "type": "department", "path": "Kunde AG › Finanzen"},
    "tags": ["erp"], "notes": "", "rate": null, "previous_ids": ["123456789"],
    "owner": {"id": "D05D…", "name": "Anna Muster", "email": "anna@example.ch"},
    "last_connected": 1791380000, "created": 1791300000, "updated": 1791381000
  }],
  "page": 1, "per_page": 50, "total": 1, "has_more": false
}

GET /computers/{id} computers:read

One computer by its id, with info as well: the system information the app collected (model, system, memory, disks …), or null.

One computer
curl -s "https://api.sharedesk.app/v1/computers/4B0E…" \
  -H "Authorization: Bearer $SHAREDESK_KEY"

POST /computers computers:write

Adds a computer to a member's address book and answers 201 with the computer (and a Location header). It fires computer.added and appears in the change log.

FieldMeaning
remote_idrequired: the ShareDesk ID, 9 digits (spaces allowed)
nameup to 120 characters
ownerthe member (ID or e-mail) whose address book it goes to; default: whoever created the key (owner_invalid if they have left)
group_ida group of that address book (group.id from /computers), or null
notesup to 2000 characters
tagsup to 20 labels of up to 30 characters

409 computer_exists when the ID is already in that address book.

Add a computer
curl -s -X POST https://api.sharedesk.app/v1/computers \
  -H "Authorization: Bearer $SHAREDESK_KEY" -H "Content-Type: application/json" \
  -d '{"remote_id": "123456789", "name": "Reception PC", "owner": "anna@example.ch"}'

PATCH /computers/{id} computers:write

Renames or moves a computer: name, group_id (null for no group), notes, tags. Other fields answer 400 field_unknown; a new ShareDesk ID is changed in the app or the account area, which keep the old one in the history. Answers the computer.

Rename and move
curl -s -X PATCH "https://api.sharedesk.app/v1/computers/4B0E…" \
  -H "Authorization: Bearer $SHAREDESK_KEY" -H "Content-Type: application/json" \
  -d '{"name": "Reception PC 2", "group_id": "9A1F…", "tags": ["reception"]}'

GET /brandings brandings:read

The team's brandings, the default one first: name, colours, contact, texts, the customer page, short link and download links (absolute), whether a logo and picture are set, and the visits and downloads of the last 30 days. Pictures themselves are not included.

Brandings
curl -s "https://api.sharedesk.app/v1/brandings" \
  -H "Authorization: Bearer $SHAREDESK_KEY"

Webhooks

Webhooks tell your tool when something happens, so it doesn't have to ask. Administrators add them under Integrations: an https address, the events, a description and on/off; up to 10 per team. Each webhook has a signing secret (whsec_…), shown once when you create it or make a new one (“New signing secret”: the old one stops at once).

EventWhendata
session.starteda session reaches our server for the first time (a few seconds after it starts){session} as in /sessions, end and billing null
session.endedthe session has ended{session} with end and billing
computer.addeda computer is added to an address book: in the app or account area, by a customer's invitation link, or with the APIthe computer as in /computers, plus via (account, invitation, api) and added_by
member.addedan administrator adds a member{member, added_by}
webhook.test“Send test event” in the account area{message, webhook_id, sent_by}, sent whatever the webhook subscribes to

Each session fires each event at most once. Sessions synced long after they happened (older than 24 hours, for example a Mac's first sync after signing in) don't fire events; read them with /sessions.

Every event is a POST to your address:

Request
POST /your/endpoint HTTP/1.1
Content-Type: application/json
User-Agent: ShareDesk-Webhooks/1.0
X-ShareDesk-Event: session.ended
X-ShareDesk-Delivery: evt_5c1d0a…
X-ShareDesk-Attempt: 1
X-ShareDesk-Signature: t=1791381003,v1=4f7c…

{"id": "evt_5c1d0a…", "type": "session.ended", "created": 1791381003, "team_id": "48EF…", "data": {"session": {…}}}
HeaderMeaning
X-ShareDesk-Eventthe event type
X-ShareDesk-Deliverythe event's ID: the same on every retry, so use it to drop duplicates
X-ShareDesk-Attempt1 for the first try, then 2, 3 …
X-ShareDesk-Signaturethe time and the signature, see Verifying signatures
member.added
{
  "id": "evt_91ab…", "type": "member.added", "created": 1791390000, "team_id": "48EF…",
  "data": {
    "member": {"id": "A11C…", "email": "lukas@example.ch", "name": "Lukas Meier",
               "first_name": "Lukas", "last_name": "Meier", "admin": false, "created": 1791390000},
    "added_by": "Anna Muster"
  }
}

Answer with any 2xx within 10 seconds: that counts as delivered. Anything else, also a redirect, counts as a failure. Do the real work after answering if it takes longer.

Verifying signatures

X-ShareDesk-Signature is t=<unix time>,v1=<signature>, where v1 is the hex HMAC-SHA256 of "<t>.<raw body>" with the webhook's signing secret. Check it before you trust an event:

  1. compute it over the raw body, before parsing the JSON;
  2. compare in constant time;
  3. refuse timestamps older than 5 minutes, against replays.
PHP
function sharedeskVerify(string $rawBody, string $header, string $secret, int $tolerance = 300): bool
{
    $parts = [];
    foreach (explode(',', $header) as $p) { [$k, $v] = array_pad(explode('=', $p, 2), 2, ''); $parts[$k] = $v; }
    if (!isset($parts['t'], $parts['v1']) || abs(time() - (int)$parts['t']) > $tolerance) return false;
    return hash_equals(hash_hmac('sha256', $parts['t'] . '.' . $rawBody, $secret), $parts['v1']);
}
$ok = sharedeskVerify(file_get_contents('php://input'), $_SERVER['HTTP_X_SHAREDESK_SIGNATURE'] ?? '', getenv('SHAREDESK_WEBHOOK_SECRET'));
Node.js
const crypto = require('crypto');
function sharedeskVerify(rawBody, header, secret, tolerance = 300) {
  const parts = Object.fromEntries(String(header).split(',').map((p) => p.split('=', 2)));
  if (!parts.t || !parts.v1 || Math.abs(Date.now() / 1000 - Number(parts.t)) > tolerance) return false;
  const mac = crypto.createHmac('sha256', secret).update(`${parts.t}.${rawBody}`).digest('hex');
  return mac.length === parts.v1.length && crypto.timingSafeEqual(Buffer.from(mac), Buffer.from(parts.v1));
}
// Express: app.post('/sharedesk', express.raw({ type: 'application/json' }), (req, res) => {
//   if (!sharedeskVerify(req.body.toString('utf8'), req.get('X-ShareDesk-Signature'), process.env.SHAREDESK_WEBHOOK_SECRET)) return res.sendStatus(400);
//   const event = JSON.parse(req.body); … res.sendStatus(204); });

Retries and the delivery log

When a delivery fails, ShareDesk tries again after 1, 3, 8, 17 and 31 minutes, that is 1, 4, 12, 29 and 60 minutes after the first attempt: 6 attempts in about an hour, then it gives up. Retries carry the same X-ShareDesk-Delivery ID and a higher X-ShareDesk-Attempt, so make your endpoint idempotent.

The account area shows each webhook's last 50 attempts with time, attempt, status code, error and duration; attempts are kept for at most 30 days. “Send test event” delivers a webhook.test right away and shows the answer.

Security

  • Keys belong on servers. The API sends no CORS headers, so a web page on another site can't call it, and a key in a browser or an app would be visible to anyone. Keep keys in your server's secret store and give each tool its own key with only the scopes it needs.
  • https only. The API answers only over https, and webhook addresses must be https URLs without a user name or password.
  • Public addresses only. A webhook's host must resolve to public addresses only, when you save it and before every attempt: local, private, link-local (cloud metadata included), shared and reserved networks are refused, in IPv4 and IPv6. Redirects are not followed and certificates are verified.
  • Signed events. Verify every webhook's signature and drop duplicates by their delivery ID.
  • Traceable. Keys, webhooks and every change made with a key are in the team's change log.

More on how ShareDesk protects sessions and accounts: Security. Found a vulnerability? Please tell us first: info@marketvision.ch.

Versioning and support

All endpoints are under /v1 of https://api.sharedesk.app; /api/v1 on the website's address answers the same. A change that would break existing integrations would come under a new version path; new fields may be added to answers and events within v1, so ignore fields you don't know.

Questions, or an endpoint you're missing? Write to support@sharedesk.ch.

Build something with ShareDesk.

Create a key under Integrations in your account, or ask us what you need.