Connect your service to TryDesk
Send customer requests and service alerts from your backend. Deliver operator replies through your own Telegram, email or other channel adapter.
1. Create an integration
In your workspace, open Integrations and create a source. Store the one-time integration key on your backend as TRYDESK_API_KEY. The key determines the workspace and source; you do not send a projectId or workspaceId.
Keep the key out of browsers, mobile applications and logs. A connector uses the HTTP APIs; it does not need direct access to TryDesk Firestore or Storage.
2. Install the Node.js SDK
SDK 0.2.0 · Node.js 22.12+ (22.x) · JavaScript / TypeScript · no runtime dependencies.
The npm release is awaiting access to the @trydesk scope. The installation command below will work after publication. The HTTP APIs are available now.
npm install @trydesk/sdk@0.2.0npm package (publication pending) · SDK reference · MIT license (SDK only)
3. Send a message
import { TryDesk, imageFromFile } from '@trydesk/sdk';
const apiKey = process.env.TRYDESK_API_KEY;
if (!apiKey) throw new Error('Set TRYDESK_API_KEY on the server');
const desk = new TryDesk({ apiKey });
const result = await desk.messages.send({
eventId: 'telegram:BOT_ID:UPDATE_ID',
externalConversationId: 'telegram-chat-42',
sender: { externalId: '42', displayName: 'Alex', kind: 'customer' },
text: 'Please help with my account',
// Optional: images: [await imageFromFile('/tmp/screenshot.png')],
});
console.log(result.conversationId, result.messageId, result.duplicate);eventId identifies a source event, not a TryDesk ticket. Keep it stable when retrying the same event. For Telegram use bot ID + update_id. The SDK generates an ID if omitted and reuses it for HTTP retries; across restarts, use your source event ID or persist it in your queue.
Keep externalConversationId stable for the external chat and sender.externalId stable for its sender. For alerts use kind: 'service' and an ID such as alarm. Each integration keeps its customers separate.
HTTP without the SDK
curl 'https://api.trydesk.io/v1/messages' \
-H "Authorization: Bearer $TRYDESK_API_KEY" \
-H 'Content-Type: application/json' \
--data '{"eventId":"event-1","externalConversationId":"chat-42","sender":{"externalId":"42"},"message":{"text":"Please help"}}'Text uses JSON. Images use multipart/form-data: one payload text field containing the JSON and repeated images file fields. The SDK sets the multipart boundary automatically.
curl 'https://api.trydesk.io/v1/messages' \
-H "Authorization: Bearer $TRYDESK_API_KEY" \
--form-string 'payload={"eventId":"image-1","externalConversationId":"chat-42","sender":{"externalId":"42"},"message":{"text":"Screenshot"}}' \
--form 'images=@./screenshot.png;type=image/png'| Input | Limit |
|---|---|
| Text / JSON | 10000 characters / 64 KB |
| Images | Up to 3 PNG, JPEG or static WebP; 10 MB each, 20 MB total |
| Pixels / multipart request | 16384 pixels per side; 40 MP; request up to 21 MB |
New events return HTTP 201. An identical retry returns 200 with duplicate: true. Reusing the same eventId with different content returns 409. API errors use {"error":{"code":"…","message":"…"}}.
400: input; 401/403: credentials or disabled source; 413: size; 415: unsupported type. Retry 429/503 after Retry-After, keeping the same event and files. Do not retry permanent validation errors.
4. Deliver operator replies
Enable replies when creating the integration and supply your Pub/Sub topic. Grant the TryDesk backend publishing permission on that topic. Your connector subscribes to it and receives identifiers only:
{ "deliveryId": "…", "workspaceId": "…", "integrationId": "…",
"conversationId": "…", "messageId": "…" }Use the same integration key to claim the delivery, read its text and external recipient, record sending intent, send through your adapter once, and confirm the provider message IDs.
const task = await desk.deliveries.claim({ deliveryId });
if (task.status === 'ready') {
const lease = { deliveryId, leaseId: task.leaseId };
const started = await desk.deliveries.start(lease);
if (started.status === 'sending') {
// Send through your channel adapter once, then confirm its IDs:
// await desk.deliveries.complete({ ...lease, providerMessageIds });
}
}| POST /v1/deliveries/… | Purpose |
|---|---|
claim | Acquire a 120-second lease; returns ready + message or skip + reason |
start | Record sending intent before contacting your provider |
complete | Confirm the provider IDs; idempotent for the same lease and IDs |
fail | Record retry, failed or unknown outcome |
Replies are ordered within each conversation. Acknowledge skip/waiting_for_previous: the predecessor will wake it. Only text replies are currently supported, up to 10000 characters; the Telegram adapter splits long text into safe parts.
A timeout may mean the provider accepted the message. Use outcome unknown for ambiguous or partial sends; do not repeat the provider call automatically. Only use retry after a definite temporary rejection. TryDesk does not guarantee exactly-once side effects at providers without idempotency support. Sent means provider acceptance, not a read receipt.
API endpoints
Default API: https://api.trydesk.io. If your network cannot reach this domain, the equivalent Firebase Hosting endpoints are:
const desk = new TryDesk({
apiKey: process.env.TRYDESK_API_KEY ?? '',
endpoint: 'https://helpdesk-1510b-api.web.app/v1/messages',
deliveryEndpoint: 'https://helpdesk-1510b-api.web.app/v1/deliveries',
});HTTP API functions run in europe-central2 (Warsaw). Hosting domains and Eventarc trigger locations are separate from the functions' execution region.
Contracts and examples
- Incoming messages: OpenAPI 3.1
- Outgoing deliveries: OpenAPI 3.1
- Postman collection — import it and set your integration key locally
Delivery calls are server-to-server POST requests with JSON bodies up to 64 KB and the same Bearer key. Do not call complete in Postman unless you actually sent the message through your provider.