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»”).
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:
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 117
X-RateLimit-Reset: 42Beyond 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": "This API key doesn't have the permission \"computers:write\".", "code": "insufficient_scope", "scope": "computers:write"}| Status | code |
|---|---|
| 400 | body_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 |
| 401 | key_missing, key_invalid (unknown, revoked or expired; with WWW-Authenticate: Bearer) |
| 403 | insufficient_scope (with scope: the one missing) |
| 404 | not_found |
| 405 | method_not_allowed (with Allow) |
| 409 | computer_exists |
| 429 | rate_limited (with Retry-After) |
| 503 | maintenance, 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:
{"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.
| Parameter | Meaning |
|---|---|
from, to | sessions that started in [from, to): unix seconds or ISO 8601 (2026-10-01, 2026-10-01T08:00:00Z) |
computer | a ShareDesk ID (9 digits) or a computer's id from /computers (then also its earlier IDs) |
technician | a member's ID or e-mail address |
direction | outgoing (a technician helped someone) or incoming |
sort | -start (default) or start |
page, per_page | see Pagination |
curl -s "https://api.sharedesk.app/v1/sessions?from=2026-09-01&to=2026-10-01&per_page=200" \
-H "Authorization: Bearer $SHAREDESK_KEY"{
"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.
curl -s "https://api.sharedesk.app/v1/computers?q=Empfang" \
-H "Authorization: Bearer $SHAREDESK_KEY"{
"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.
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.
| Field | Meaning |
|---|---|
remote_id | required: the ShareDesk ID, 9 digits (spaces allowed) |
name | up to 120 characters |
owner | the member (ID or e-mail) whose address book it goes to; default: whoever created the key (owner_invalid if they have left) |
group_id | a group of that address book (group.id from /computers), or null |
notes | up to 2000 characters |
tags | up to 20 labels of up to 30 characters |
409 computer_exists when the ID is already in that address book.
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.
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.
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).
| Event | When | data |
|---|---|---|
session.started | a session reaches our server for the first time (a few seconds after it starts) | {session} as in /sessions, end and billing null |
session.ended | the session has ended | {session} with end and billing |
computer.added | a computer is added to an address book: in the app or account area, by a customer's invitation link, or with the API | the computer as in /computers, plus via (account, invitation, api) and added_by |
member.added | an 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:
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": {…}}}| Header | Meaning |
|---|---|
X-ShareDesk-Event | the event type |
X-ShareDesk-Delivery | the event's ID: the same on every retry, so use it to drop duplicates |
X-ShareDesk-Attempt | 1 for the first try, then 2, 3 … |
X-ShareDesk-Signature | the time and the signature, see Verifying signatures |
{
"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:
- compute it over the raw body, before parsing the JSON;
- compare in constant time;
- refuse timestamps older than 5 minutes, against replays.
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'));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.