Contents

Webhooks

Up to 10 HTTPS endpoints per key, each with the events it wants and its own signing secret. Webhooks can be managed with a read-only key too: receiving news does not change the catalog.

Base URL, authentication and conventions of this API are on the Catalog API page.

get/webhooks

List webhooks

GET https://api-catalog.nucleoplatform.com/api/catalog/v1/webhooks
Authentication: Bearer token
Rate limit: 600 requests per 1m, per key (default; the catalog owner can set 1–6,000)

Responses

  • 200The webhooks of this key (without secrets).
    • dataarray of Webhookrequired
      Attributes of each item
      • idstring (uuid)
      • urlstring
      • eventsarray of string
        One ofproduct.createdproduct.updatedproduct.deletedstock.updated
      • activeboolean
      • last_success_atstring (date-time) | null
      • last_failure_atstring (date-time) | null
      • last_errorstring | null
        Example: HTTP 503
      • created_atstring (date-time)
Request
curl -X GET https://api-catalog.nucleoplatform.com/api/catalog/v1/webhooks \
  -H "Authorization: Bearer $NUCLEO_ACCESS_TOKEN" \
  -H 'Accept: application/json'
Response
{
  "data": [
    {
      "id": "9b2f4c1e-5d7a-4e8b-9c3d-2a1f0e6b7c8d",
      "url": "string",
      "events": [
        "product.created"
      ],
      "active": true,
      "last_success_at": "2026-10-01T09:30:00Z",
      "last_failure_at": "2026-10-01T09:30:00Z",
      "last_error": "HTTP 503",
      "created_at": "2026-10-01T09:30:00Z"
    }
  ]
}
post/webhooks

Create a webhook

The URL must be https and resolve to a public address. The answer contains the signing secret (whsec_…) — the only time it is shown.

POST https://api-catalog.nucleoplatform.com/api/catalog/v1/webhooks
Authentication: Bearer token
Rate limit: 600 requests per 1m, per key (default; the catalog owner can set 1–6,000)

Headers

  • Idempotency-Keystring

    Any string of 1–255 printable ASCII characters, unique per change you mean (a UUID is fine). Sending the same request again with the same key within 48 hours returns the first answer without doing the work again (header Idempotent-Replayed: true). The same key with a different request is a 409 idempotency_key_reused; while the first request is still running, 409 idempotency_key_in_progress with Retry-After: 1. Answers 429 and 5xx are not stored: retry them with the same key.

    max length 255
    Example: 2b5c0d2e-7d2a-4f6e-9a51-0c8a1e7f3b44

Request bodyapplication/json

  • urlstring (uri)required
    max length 500
  • eventsarray of stringrequired
    One ofproduct.createdproduct.updatedproduct.deletedstock.updated
    min items 1

Responses

  • 201Created. Store the secret now.
    • dataWebhook & objectrequired
      Child attributes
      • idstring (uuid)
      • urlstring
      • eventsarray of string
        One ofproduct.createdproduct.updatedproduct.deletedstock.updated
      • activeboolean
      • last_success_atstring (date-time) | null
      • last_failure_atstring (date-time) | null
      • last_errorstring | null
        Example: HTTP 503
      • created_atstring (date-time)
      • secretstringrequired

        Shown only now.

        Example: whsec_3KQ9…
  • 400The request must change: validation_failed (see details, one list of messages per field), invalid_json, invalid_cursor, product_not_written, variant_not_written, not_written, image_not_downloadable.
    • errorobjectrequired
      Child attributes
      • codestringrequired

        Stable machine-readable code. Branch on it, not on the message.

      • messagestringrequired
      • request_idstringrequired

        Same as the X-Request-Id header. Quote it to support.

      • detailsobject
  • 409field_rule (the key's field rule does not allow this change), field_locked (the change touches fields another connected system owns; details.locked lists them), idempotency_key_reused, idempotency_key_in_progress, webhook_limit.
    • errorobjectrequired
      Child attributes
      • codestringrequired

        Stable machine-readable code. Branch on it, not on the message.

      • messagestringrequired
      • request_idstringrequired

        Same as the X-Request-Id header. Quote it to support.

      • detailsobject
Request
curl -X POST https://api-catalog.nucleoplatform.com/api/catalog/v1/webhooks \
  -H "Authorization: Bearer $NUCLEO_ACCESS_TOKEN" \
  -H 'Idempotency-Key: 2b5c0d2e-7d2a-4f6e-9a51-0c8a1e7f3b44' \
  -H 'Content-Type: application/json' \
  -d '{
  "url": "https://erp.acme.example/nucleo/webhooks",
  "events": [
    "product.created",
    "product.updated",
    "product.deleted",
    "stock.updated"
  ]
}'
Response
{
  "data": {
    "id": "9b2f4c1e-5d7a-4e8b-9c3d-2a1f0e6b7c8d",
    "url": "string",
    "events": [
      "product.created"
    ],
    "active": true,
    "last_success_at": "2026-10-01T09:30:00Z",
    "last_failure_at": "2026-10-01T09:30:00Z",
    "last_error": "HTTP 503",
    "created_at": "2026-10-01T09:30:00Z",
    "secret": "whsec_3KQ9…"
  }
}
get/webhooks/{webhook}

Get a webhook

GET https://api-catalog.nucleoplatform.com/api/catalog/v1/webhooks/{webhook}
Authentication: Bearer token
Rate limit: 600 requests per 1m, per key (default; the catalog owner can set 1–6,000)

Path parameters

  • webhookstring (uuid)required

Responses

  • 200The webhook, with the outcome of its last deliveries.
    • dataWebhookrequired
      Child attributes
      • idstring (uuid)
      • urlstring
      • eventsarray of string
        One ofproduct.createdproduct.updatedproduct.deletedstock.updated
      • activeboolean
      • last_success_atstring (date-time) | null
      • last_failure_atstring (date-time) | null
      • last_errorstring | null
        Example: HTTP 503
      • created_atstring (date-time)
  • 404product_not_found, variant_not_found, image_not_found, import_not_found, webhook_not_found, or not_found for a path that does not exist.
    • errorobjectrequired
      Child attributes
      • codestringrequired

        Stable machine-readable code. Branch on it, not on the message.

      • messagestringrequired
      • request_idstringrequired

        Same as the X-Request-Id header. Quote it to support.

      • detailsobject
Request
curl -X GET 'https://api-catalog.nucleoplatform.com/api/catalog/v1/webhooks/{webhook}' \
  -H "Authorization: Bearer $NUCLEO_ACCESS_TOKEN" \
  -H 'Accept: application/json'
Response
{
  "data": {
    "id": "9b2f4c1e-5d7a-4e8b-9c3d-2a1f0e6b7c8d",
    "url": "string",
    "events": [
      "product.created"
    ],
    "active": true,
    "last_success_at": "2026-10-01T09:30:00Z",
    "last_failure_at": "2026-10-01T09:30:00Z",
    "last_error": "HTTP 503",
    "created_at": "2026-10-01T09:30:00Z"
  }
}
patch/webhooks/{webhook}

Update a webhook or rotate its secret

With rotate_secret: true the answer contains the new secret; the old one stops working at once.

PATCH https://api-catalog.nucleoplatform.com/api/catalog/v1/webhooks/{webhook}
Authentication: Bearer token
Rate limit: 600 requests per 1m, per key (default; the catalog owner can set 1–6,000)

Path parameters

  • webhookstring (uuid)required

Headers

  • Idempotency-Keystring

    Any string of 1–255 printable ASCII characters, unique per change you mean (a UUID is fine). Sending the same request again with the same key within 48 hours returns the first answer without doing the work again (header Idempotent-Replayed: true). The same key with a different request is a 409 idempotency_key_reused; while the first request is still running, 409 idempotency_key_in_progress with Retry-After: 1. Answers 429 and 5xx are not stored: retry them with the same key.

    max length 255
    Example: 2b5c0d2e-7d2a-4f6e-9a51-0c8a1e7f3b44

Request bodyapplication/json

  • urlstring (uri)
    max length 500
  • eventsarray of string
    One ofproduct.createdproduct.updatedproduct.deletedstock.updated
    min items 1
  • activeboolean

    An inactive webhook receives nothing; events of that time are not sent later.

  • rotate_secretboolean

Responses

  • 200Updated.
    • dataWebhook & objectrequired
      Child attributes
      • idstring (uuid)
      • urlstring
      • eventsarray of string
        One ofproduct.createdproduct.updatedproduct.deletedstock.updated
      • activeboolean
      • last_success_atstring (date-time) | null
      • last_failure_atstring (date-time) | null
      • last_errorstring | null
        Example: HTTP 503
      • created_atstring (date-time)
      • secretstring

        Only after rotate_secret.

  • 400The request must change: validation_failed (see details, one list of messages per field), invalid_json, invalid_cursor, product_not_written, variant_not_written, not_written, image_not_downloadable.
    • errorobjectrequired
      Child attributes
      • codestringrequired

        Stable machine-readable code. Branch on it, not on the message.

      • messagestringrequired
      • request_idstringrequired

        Same as the X-Request-Id header. Quote it to support.

      • detailsobject
  • 404product_not_found, variant_not_found, image_not_found, import_not_found, webhook_not_found, or not_found for a path that does not exist.
    • errorobjectrequired
      Child attributes
      • codestringrequired

        Stable machine-readable code. Branch on it, not on the message.

      • messagestringrequired
      • request_idstringrequired

        Same as the X-Request-Id header. Quote it to support.

      • detailsobject
Request
curl -X PATCH 'https://api-catalog.nucleoplatform.com/api/catalog/v1/webhooks/{webhook}' \
  -H "Authorization: Bearer $NUCLEO_ACCESS_TOKEN" \
  -H 'Idempotency-Key: 2b5c0d2e-7d2a-4f6e-9a51-0c8a1e7f3b44' \
  -H 'Content-Type: application/json' \
  -d '{
  "url": "https://shop.acme.example",
  "events": [
    "product.created"
  ],
  "active": true,
  "rotate_secret": true
}'
Response
{
  "data": {
    "id": "9b2f4c1e-5d7a-4e8b-9c3d-2a1f0e6b7c8d",
    "url": "string",
    "events": [
      "product.created"
    ],
    "active": true,
    "last_success_at": "2026-10-01T09:30:00Z",
    "last_failure_at": "2026-10-01T09:30:00Z",
    "last_error": "HTTP 503",
    "created_at": "2026-10-01T09:30:00Z",
    "secret": "string"
  }
}
delete/webhooks/{webhook}

Delete a webhook

DELETE https://api-catalog.nucleoplatform.com/api/catalog/v1/webhooks/{webhook}
Authentication: Bearer token
Rate limit: 600 requests per 1m, per key (default; the catalog owner can set 1–6,000)

Path parameters

  • webhookstring (uuid)required

Responses

  • 204Deleted. Pending deliveries are dropped.
  • 404product_not_found, variant_not_found, image_not_found, import_not_found, webhook_not_found, or not_found for a path that does not exist.
    • errorobjectrequired
      Child attributes
      • codestringrequired

        Stable machine-readable code. Branch on it, not on the message.

      • messagestringrequired
      • request_idstringrequired

        Same as the X-Request-Id header. Quote it to support.

      • detailsobject
Request
curl -X DELETE 'https://api-catalog.nucleoplatform.com/api/catalog/v1/webhooks/{webhook}' \
  -H "Authorization: Bearer $NUCLEO_ACCESS_TOKEN"
Response
HTTP 204 — Deleted. Pending deliveries are dropped.
WebhookcatalogEvent

Something changed in the catalog

Sent to every active webhook that subscribed to the event. The notice is small: it says what changed and you read the product with GET /products/{id} if you need it.

  • product.created — a product was created, or restored from the trash.
  • product.updated — a product changed; changed_fields names the fields (for example title, description, price:eu, attr:color, images, stock for the in/out of stock state).
  • product.deleted — a product was moved to the trash.
  • stock.updated — the available quantity of a variant at a location changed (on the product page, by an import or through this API).

Changes made by any key, including yours, are sent: triggered_by_this_key is true when the change came from the key that owns the webhook, so you can skip your own echoes.

Signature. X-Nucleo-Signature: t=<unix time>,v1=<signature>, where the signature is the lowercase hex HMAC-SHA256 of <t>.<raw body> keyed with the webhook's secret. Verify it on the exact bytes received, compare in constant time and reject a t older than 5 minutes.

Delivery. 10-second timeout, redirects not followed; any 2xx is a success. Deliveries leave within about a minute of the change. Any other answer is retried about 30 s, 1, 2, 4, 8, 16 and 32 minutes later (8 attempts in all), then the event is dropped. Every attempt carries the same id (also in X-Nucleo-Webhook-Id) and its number in X-Nucleo-Attempt. Events can arrive out of order: compare created_at, or re-read the product.

Headers

  • X-Nucleo-Signaturestringrequired
    Example: t=1791115200,v1=5f2b6c0e9a8d4f7b1c3e2a6d9b0f8e7c6a5d4b3c2e1f0a9b8c7d6e5f4a3b2c1d
  • X-Nucleo-Eventstringrequired
    One ofproduct.createdproduct.updatedproduct.deletedstock.updated
    Example: product.created
  • X-Nucleo-Webhook-Idstring (uuid)required
  • X-Nucleo-Attemptintegerrequired
    min 1max 8

Request Nucleo sendsapplication/json

  • idstring (uuid)required

    Same at every attempt.

  • typestringrequired
    One ofproduct.createdproduct.updatedproduct.deletedstock.updated
  • created_atstring (date-time)required
  • triggered_by_this_keybooleanrequired
  • dataobjectrequired
    Child attributes
    • product_idinteger
    • skustring | null
    • changed_fieldsarray of string

      Only in product.updated.

    • variant_idinteger

      Only in stock.updated.

    • variant_skustring | null
    • locationstring
    • availableinteger | null

Expected response

  • 200Received. Any 2xx works; the body is ignored.
Body
{
  "id": "5d1c9a0e-2b7f-4c3a-9e8d-6f1a2b3c4d5e",
  "type": "product.updated",
  "created_at": "2026-10-14T08:00:00Z",
  "triggered_by_this_key": false,
  "data": {
    "product_id": 1201,
    "sku": "TEE-001",
    "changed_fields": [
      "title",
      "price:eu"
    ]
  }
}
Response
HTTP 200 — Received. Any `2xx` works; the body is ignored.
Was this page helpful?