Developers

Webhooks#

Two kinds of webhooks connect your application to NAMES LEGAL:

Direction Event Used by
NAMES LEGAL → you site.ready Embedded purchase
You → NAMES LEGAL connector trigger Data connector

site.ready#

Sent to the notification address of your sales channel when a site bought through your channel is paid and ready to use.

POST /hooks/names-legal HTTP/1.1
Host: app.example.com
Content-Type: application/json
X-NamesLegal-Signature: sha256=5d41402abc4b2a76b9719d911017c592...
{
  "event": "site.ready",
  "channel": "app-ecole",
  "reference": "instance-42",
  "site_url": "https://ecolehorizon.names.legal",
  "console_url": "https://ecolehorizon.names.legal/cms/",
  "name": "École Horizon",
  "email": "direction@ecole.ch",
  "created_at": "2026-09-24T14:02:11+00:00"
}

reference is the data-ref you passed to the purchase frame: use it to find your user.

Verifying the signature#

The signature is an HMAC-SHA256 of the raw body with your channel's signing secret. Always check it before trusting the message.

Python

import hashlib, hmac

def is_valid(raw_body: bytes, header: str, secret: str) -> bool:
    expected = "sha256=" + hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, header or "")

Node.js

const crypto = require("crypto");

function isValid(rawBody, header, secret) {
  const expected = "sha256=" + crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
  return header && crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(header));
}

PHP

$expected = 'sha256=' . hash_hmac('sha256', $rawBody, $secret);
$valid = hash_equals($expected, $_SERVER['HTTP_X_NAMESLEGAL_SIGNATURE'] ?? '');

Delivery#

  • Answer with any 2xx status within 10 seconds.
  • On failure, delivery is retried with growing delays (from one minute up to one hour) for several hours.
  • The same event may exceptionally arrive twice: make your handler idempotent, for example on site_url.

Connector incoming webhook#

When a site owner connects your API as a data source, their console shows a webhook address unique to that connection:

https://<site>/connectors/hook/<id>/<token>/

Call it with an empty POST whenever your data changes:

curl -X POST "https://ecolehorizon.names.legal/connectors/hook/12/Qm9...Zg/"
  • The answer is 202 Accepted; the synchronisation runs in the background within a minute.
  • Calls in bursts are merged: at most one synchronisation per minute and per connection.
  • The token is the secret. The site owner can replace it from the console at any time; the old address then answers 404.