Skip to content

Webhooks

Webhooks let Semantico notify your systems the moment a product generation task finishes — so you don’t have to poll. Semantico supports one webhook configuration per workspace.

Manage your webhook through the settings endpoints:

  • GET /settings/webhooks/ — retrieve the current configuration.
  • POST /settings/webhooks/ — create or replace the configuration (a POST always replaces the single existing config).
  • DELETE /settings/webhooks/ — remove it.

Request body:

{
"url": "https://example.com/webhook",
"hmac_secret": "your-shared-secret",
"actions": ["product_generated", "product_generation_failed", "product_generation_no_urls"]
}
  • url (required) — where deliveries are sent.
  • hmac_secret (optional) — if set, every delivery is signed so you can verify it came from Semantico.
  • actions (optional) — which events to deliver. If omitted, all events are enabled.

Available events:

Event Fires when
product_generated A product finished generating successfully.
product_generation_failed Generation failed for a product.
product_generation_no_urls No source URLs could be found for the product.
  • Deliveries are POST requests with Content-Type: application/json.
  • Timeout is 10 seconds.
  • Failed deliveries are retried up to 5 times with backoff (roughly after 1s, 8s, 60s, 120s, and 420s). A 2xx is treated as success; a 4xx is treated as permanent and is not retried; other responses (5xx, timeouts, connection errors) are retried.
  • Semantico won’t notify you twice for the same product-and-event pair.

Each delivery contains:

  • action — the event name.
  • status — the task status.
  • reason_for_failure — an optional failure reason.
  • credits — credits consumed and remaining.
  • task — task metadata (id, timestamps, source URLs).
  • product — the full product payload (or null if unavailable). Custom attributes are returned under the sections key.
{
"action": "product_generated",
"status": "SUCCESS",
"reason_for_failure": "",
"credits": { "consumed": 10, "remaining": 1230 },
"task": {
"id": "b3b8c9c8-4a62-4b59-9caa-7d7b1f5a1234",
"status": "SUCCESS",
"created_at": "2026-02-09T10:00:00Z",
"updated_at": "2026-02-09T10:01:00Z",
"urls": [
{
"id": 1,
"url": "https://example.com/product",
"status": "SUCCESS",
"relevant_score": 0.95,
"is_user_provided_link": true
}
]
},
"product": {
"id": 123,
"sku": "MODEL-001",
"is_product_model": true
}
}

If you set an hmac_secret, each delivery includes two headers:

  • X-Webhook-Timestamp — Unix timestamp (seconds) of the delivery.
  • X-Webhook-Signaturesha256=<hex>, an HMAC-SHA256 of the signed payload.

The signed payload is the timestamp and the raw request body joined by a dot:

signed_payload = "<X-Webhook-Timestamp>" + "." + "<raw JSON request body>"
signature = "sha256=" + HMAC_SHA256(secret, signed_payload) // hex digest

To verify, recompute the signature over the raw body you received and compare it against X-Webhook-Signature. If no hmac_secret is configured, these headers are not sent.

Verifying in Python:

import hashlib
import hmac
def is_valid(secret: str, timestamp: str, raw_body: bytes, signature: str) -> bool:
signed = f"{timestamp}.".encode() + raw_body
expected = "sha256=" + hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature)