Skip to content

Integration recipes

n8n

  • Calling the API: HTTP Request node → Authentication Generic Credential Type → Header Auth, Name Authorization, Value Bearer dpk_xxx. URLs look like https://<domain>/api/v1/....
  • Receiving events: Webhook node (POST), enable Options → Raw Body. Copy the Production URL, then register it with POST /api/v1/webhooks. Verify the signature with a Crypto node (HMAC, SHA256, hex) over the string <X-Deplao-Timestamp>.<raw body>.
  • Example: new order (Webhook from your online store) → HTTP Request POST /api/v1/accounts/{account_id}/conversations/{thread_id}/messages with the body {"text": "Thank you for your order #{{$json.order_id}}"}.

Make (Integromat)

  • Calling the API: HTTP → Make a request module, header Authorization: Bearer dpk_xxx, Body type Raw, Content type JSON (application/json).
  • Receiving events: Webhooks → Custom webhook, copy the address, then register a Deplao webhook with the events you need. If your scenario can't verify the signature itself, keep the webhook address secret (Make generates a long random address) and use HTTPS only.

Google Apps Script / Google Sheets

Apps Script can't read the headers of incoming requests (so it can't verify signatures) and answers POST requests with a 302, so don't use webhooks. Use polling with a time-driven trigger instead (Triggers → Time-driven → every minute):

js
const BASE = 'https://<domain>/api/v1';

function pollDeplao() {
  const props = PropertiesService.getScriptProperties();
  const key = props.getProperty('DEPLAO_KEY');
  const since = Number(props.getProperty('since') || 0);
  const res = UrlFetchApp.fetch(BASE + '/events?types=message.received&limit=200&since=' + since, {
    headers: { Authorization: 'Bearer ' + key },
    muteHttpExceptions: true,
  });
  const body = JSON.parse(res.getContentText());
  if (!body.success) throw new Error(body.error.code + ': ' + body.error.message);
  const sheet = SpreadsheetApp.getActive().getSheetByName('Messages');
  body.data.forEach(function (ev) {
    const conv = ev.data.conversation || {};
    const msg = ev.data.message || {};
    sheet.appendRow([new Date(ev.ts), ev.account_id, conv.display_name, msg.text]);
  });
  props.setProperty('since', String(body.pagination.next_since));
}

Your own worker or server (calling the API)

js
const res = await fetch('https://<domain>/api/v1/accounts/0501234567/conversations/8765432109876/messages', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer ' + process.env.DEPLAO_KEY,
    'Content-Type': 'application/json',
    'Idempotency-Key': 'order-1001-shipped', // resending with the same key → no duplicate message
  },
  body: JSON.stringify({ text: 'Order #1001 has been handed over to the courier', thread_type: 'user' }),
});
const out = await res.json();
if (!out.success) console.error(out.error.code, out.error.message);
  • Idempotency-Key is remembered for 24 hours (or until the app restarts). Resending with the same key returns the result of the first call unchanged.
  • Group chats: "thread_type": "group".

Generating SDKs and tooling

bash
npx @openapitools/openapi-generator-cli generate -i http://127.0.0.1:9900/api/v1/openapi.json -g typescript-fetch -o deplao-sdk
  • Postman, Insomnia, Bruno: Import → URL http://127.0.0.1:9900/api/v1/openapi.json.
  • By default openapi.json can be viewed without a key. If you've turned off "Public docs" (Tài liệu công khai), add an Authorization header when importing remotely.

Didn't find your answer?

Message us on Telegram