Method PUT/partner/webhooks/{webhook_id}

Modify a notification subscription: its destination URL, its event list, its signing secret, whether it is active. Scope webhooks:write.

On this page

You modify a notification subscription that your brand already owns, and you receive the subscription in its new state.

#Authorization

Send your API key in the Authorization header, in the form Bearer followed by a space then the key. The key must carry the webhooks:write scope. A key that does not carry this scope receives a 403 whose message names the missing scope.

What we requireValue
AuthenticationAPI key of your brand
Scope carried by the keywebhooks:write
Feature of your planwebhook notifications

Two conditions come on top of the scope of the key.

  • The subscription must belong to the brand of the key. We look for the subscription by its number and by your brand. When that lookup finds nothing, you receive a 404. A subscription that belongs to another brand gives exactly the same response. This endpoint therefore never tells you that a number exists elsewhere.
  • The plan of your brand must include notifications. Otherwise you receive a 403 carrying the FEATURE_NOT_AVAILABLE code. One exception exists, described just below.

The full URL of this endpoint is https://api.sealtrust.io/v1/partner/webhooks/{webhook_id}. The same endpoint also answers without the /v1 prefix, at https://api.sealtrust.io/partner/webhooks/{webhook_id}. Both URLs call the same code. Use the /v1 form for a new integration.

#Rate limit

We measure the rate over a fixed 60 second window. The ceiling rises with your plan, and we can set a value on your brand that wins over the one of your plan. We therefore read, in this order: the value set on your brand, then the one of your plan, then a fallback value of 120 calls per window. That fallback value is used only if your brand and your plan carry none.

Do not guess your ceiling of the moment. You read it on every response that gets past the rate check.

Two counters overlap, with the same ceiling: one per key, one for the sum of all the keys of your brand. Creating extra keys therefore does not raise the total rate allowed.

Four headers describe the more constraining of the two counters.

HeaderContent
X-RateLimit-Limitthe ceiling applied over the window
X-RateLimit-Remainingwhat is left to you in the current window
X-RateLimit-Resetthe end timestamp of the window, in seconds
X-RateLimit-Scopekey or brand, the counter that served as the reference

A rate refusal returns 429 with Retry-After, expressed in seconds remaining in the current window. That value is never below 1.

This endpoint consumes no daily quota of a key and no monthly quota of a plan. The rate ceiling is the only counter that applies here.

#Path and query parameters

NameTypeRequiredDescription
webhook_idintegeryesThe number of the subscription to modify, in the path. A value that is not an integer gives a 422.

This endpoint has no query parameter.

#Headers

NameTypeRequiredDescription
AuthorizationstringyesBearer followed by a space then your API key.
Content-Typestringyesapplication/json.
Idempotency-KeystringnoThis endpoint does not declare this header. It neither reads it nor remembers it.

#Request body

The body is a JSON object. The four fields are optional. Send only the fields you want to change. A field absent from the body keeps its value.

NameTypeRequiredDescription
urlstringnoThe new destination URL, from 10 to 2048 characters. It must start with https://. Never send null in this field, read the warning below.
eventsarray of stringnoThe new list of event types. It replaces the old list entirely. Every value must belong to the list below.
is_activebooleannotrue to receive the events, false to stop the deliveries without destroying the subscription. This field accepts true or false. Omit it if you do not want to change it.
secretstringnoThe new signing secret, up to 128 characters. We use it to compute the X-Webhook-Signature header of every delivery. null erases the secret, and the following deliveries then go out without a signature.

The server refuses any field that this table does not name. An unknown field makes the request fail with a 422, and we modify nothing.

An empty body, written {}, is valid. It modifies nothing, it returns the subscription unchanged, and we require the plan as for any other modification.

#The 23 event types

A value of events that is not in this list makes the request fail with a 422, and the message names the rejected values.

FamilyTypes
Product lifecycleproduct.minted, product.transferred, product.burned, product.status_changed
Batchesbatch.completed, batch.failed
Certificatecertificate.issued
Distribution and securityproduct.scanned, product.gray_market, clone.alert, transfer.accepted
Returnsreturn.requested, return.received, return.completed, return.rejected, return.expired
Warrantywarranty.claimed, warranty.expiring_soon
Buybackbuyback.offered, buyback.accepted, buyback.declined, buyback.completed, buyback.expired

#Example request

You repoint subscription number 128 to a new URL and you cut its list down to two event types.

curl -i -X PUT https://api.sealtrust.io/v1/partner/webhooks/128 \
  -H "Authorization: Bearer st_test_0000000000000000000000000000000000000000000000" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://exemple-sas.example.com/sealtrust/evenements",
    "events": ["product.minted", "batch.completed"]
  }'

#Example response

HTTP code 200.

JSON
{
  "id": 128,
  "brand_id": 12,
  "url": "https://exemple-sas.example.com/sealtrust/evenements",
  "events": ["product.minted", "batch.completed"],
  "is_active": true,
  "health": "healthy",
  "created_at": "2026-08-18T09:12:44.512038+00:00",
  "updated_at": "2026-08-20T14:03:21.884517+00:00"
}

The response has eight fields and nothing else. The secret never appears in it.

FieldTypeDescription
idintegerThe number of the subscription.
brand_idintegerThe number of your brand.
urlstringThe destination URL recorded. Read it again after every modification.
eventsarray of stringThe list of event types recorded.
is_activebooleantrue if the subscription receives the events.
healthstringhealthy or degraded. It is degraded after the definitive failure of a delivery, and comes back to healthy on the first successful delivery.
created_atstringThe creation date of the subscription, in Universal Time.
updated_atstringThe date of the last modification, in Universal Time.

#Errors

The body of an error response carries a detail field. Depending on the case, that field contains a sentence, a list or an object.

CodeConditionWhat to do
401The Authorization header is missing. detail is Missing Authorization header. The response also carries WWW-Authenticate: Bearer.Add the header.
401The Authorization header does not start with Bearer followed by a space. The response also carries WWW-Authenticate: Bearer.Fix the form of the header.
401The key sent is empty, or shorter than 40 characters. detail is Invalid API key format.Send the whole key. A key truncated on screen gives this response.
401The key sent is unknown. detail is Invalid API key.Check that you are sending the complete key, with no space and no line break.
403The key is no longer active, because it was revoked. detail names its state.Create a new key in the console.
403The key has reached its expiry date. detail is API key has expired.Create a new key. The old one will never become valid again.
403The key does not carry the webhooks:write scope. detail is Missing required scope: webhooks:write.Create a key carrying this scope. The scopes of an existing key cannot be modified.
403The plan of your brand does not include notifications. detail is {"code": "FEATURE_NOT_AVAILABLE", "feature": "webhooks"}.Change plan from the console, or contact us. You can still switch the subscription off with a body reduced to {"is_active": false}.
404No subscription carries this number for your brand. detail is Webhook subscription not found.Check the number with GET /v1/partner/webhooks. You receive the same response if the subscription belongs to another brand.
422The webhook_id of the path is not an integer.Send the number returned by GET /v1/partner/webhooks.
422The webhook_id of the path is an integer too large to be a subscription number. The message speaks of a query parameter, whereas the offending value is in the path.Send the number returned by GET /v1/partner/webhooks.
422The body contains a field that this endpoint does not know.Remove that field. We accept only url, events, is_active and secret.
422url is a string that does not start with https://.Fix the URL so that it starts with https://.
422url is a string of fewer than 10 or more than 2048 characters.Fix the length of the URL.
422events contains at least one unknown type. The message names the rejected values.Take the values from the table of the 23 event types.
422secret exceeds 128 characters.Shorten the secret.
422A field does not carry the announced type, for example url receives a number or is_active receives a string.Fix the type. The message names the offending field.
422The body is not a JSON object, or the body is missing.Send a JSON object, even an empty one, with Content-Type: application/json.
429The rate ceiling of the key is reached. The Retry-After header and the X-RateLimit-* family accompany the response, with X-RateLimit-Scope: key.Wait the number of seconds given by Retry-After, then try again.
429The rate ceiling of the brand is reached, across all keys. X-RateLimit-Scope is brand.Wait the number of seconds given by Retry-After. Creating an extra key does not raise this ceiling.
500An unexpected error occurred. detail is Internal Server Error.Try again. If the error persists, contact support giving the X-Request-Id header of the response.
503The call rate limiting service is momentarily unavailable. We refuse the call before any read.Try again in a few moments. The subscription was not modified.

#See also

Your answer opens a pre-filled email in your mail app, addressed to contact@sealtrust.io. You read it over before sending it.

Suggest a correctionReport a problem