Agent skill
Lokalise Webhooks Skill
Receive and authenticate Lokalise webhooks. Use when setting up a Lokalise webhook handler, checking the X-Secret header, switching to X-Api-Key or a custom header, debugging 401s or the setup ping, or handling events like project.translation.updated, project.keys.added and project.task.closed.
Install this skill
npx skills add hookdeck/webhook-skills --skill lokalise-webhooks
Lokalise (translation management) sends webhook events as HTTP POST requests when translations, keys, tasks and files change in a project. Lokalise does not sign the payload: it sends the webhook secret, unchanged, in a request header (X-Secret by default), so the endpoint authenticates each request by comparing that header with its stored secret.
When to Use This Skill
- How do I receive Lokalise webhooks?
- How do I verify the Lokalise
X-Secretheader? - Does Lokalise sign webhook payloads? (No: shared secret in a header)
- How do I use
X-Api-Keyor a custom header instead ofX-Secret? - Why does the Lokalise webhook ping fail when I save the webhook?
- How do I handle
project.translation.updatedorproject.keys.addedevents?
Verification (core)
| Lokalise setting | Header received |
|---|---|
| Secret (default) | X-Secret: <secret> |
| Secret, sent as API key | X-Api-Key: <secret> |
| Custom header | <your header name>: <your value> |
const crypto = require('crypto');
// Hash both sides: equal-length buffers, so timingSafeEqual never throws.
function safeEqual(a, b) {
const ha = crypto.createHash('sha256').update(String(a)).digest();
const hb = crypto.createHash('sha256').update(String(b)).digest();
return crypto.timingSafeEqual(ha, hb);
}
function verifyLokaliseRequest(headers, config = process.env) {
const secret = config.LOKALISE_WEBHOOK_SECRET;
const headerName = (config.LOKALISE_WEBHOOK_HEADER || 'X-Secret').toLowerCase();
if (!secret) return false; // never accept when unconfigured
const received = headers[headerName]; // Node lowercases header names
return Boolean(received) && safeEqual(received, secret);
}
Return 401 when this fails and 200 once handled. There is no signature, so the body is not part of verification, but read it raw (express.raw({ type: '*/*' })) and authenticate before parsing so any content type works. Python uses hmac.compare_digest the same way; see references/verification.md.
For complete handlers with tests, see examples/express/, examples/nextjs/, examples/fastapi/.
Event Types
The JSON body carries the event name in event (also sent in the X-Event header).
| Event | Fires When |
|---|---|
project.translation.updated | A translation was modified |
project.translations.updated | Translations changed in a bulk action (up to 300 per event) |
project.key.added / project.keys.added | A key was added / keys were added in bulk |
project.key.modified / project.keys.modified | A key was modified / keys were modified in bulk |
project.keys.deleted | Keys were deleted |
project.task.closed | A task was closed (manually or on completion) |
project.imported | Translation files were uploaded to the project |
The full list (exports, branches, languages, contributors, orders, tasks) is in references/overview.md. Lokalise also sends a ping when a webhook is created; it only needs a 2xx. Respond within 8 seconds or Lokalise retries for up to 24 hours, then disables the webhook.
Environment Variables
LOKALISE_WEBHOOK_SECRET=your-lokalise-webhook-secret # Apps > Webhooks > your webhook
LOKALISE_WEBHOOK_HEADER=X-Secret # or X-Api-Key / your custom header name
Local Development
Lokalise can't reach localhost. Tunnel with the Hookdeck CLI (no account required):
npx hookdeck-cli listen 3000 lokalise --path /webhooks/lokalise
Use the printed URL as the webhook URL in the Lokalise Webhooks app.
Resources
- references/overview.md - How Lokalise webhooks work, event list, payload shape
- references/setup.md - Install the Webhooks app, choose the secret header, select events
- references/verification.md - Header check, IP allowlist, gotchas, debugging 401s
- examples/ - Runnable Express, Next.js and FastAPI handlers with tests