Skip to content
YutaiDocs
GET /v1/statusGet API key

Integrate / Webhooks

Webhooks

What Yutai's webhooks send: the kinds of change they tell a distributor about, what one delivery carries, how often a failed delivery is tried again, and how a delivery is checked. The values on this page are read from Yutai's own rules when the site is built, so they cannot drift from them.

View as .md

Yutai does not deliver to real endpoints yet. The deliveries it records run on simulated data, so no change reaches a real address; the rules on this page are the ones its stored deliveries already follow.

Kinds of change

Every delivery tells a distributor about one change, and every change is one kind. A distributor asks for the kinds of change it wants to hear about; the kinds Yutai's registry names:

Tier change tier_changed
A holder's tier changed: the credential the holder carries now names another tier.
Benefit unlock benefit_unlocked
A benefit opened through a tier: the benefit and the tier that opens it.
Claim confirmation claim_confirmed
A claim a holder made is recorded: the claim and the benefit it was made on.
Redemption record redemption_recorded
A redemption of a claim is recorded.

What a delivery carries

One delivery carries three facts: the event id, the kind and the payload. The bounds are the contracts' own:

eventId
The change's own id. It names one change and never changes across attempts, so you can tell a repeat from a new change. It carries 1 to 256 characters of letters, digits, dot, underscore, colon and hyphen.
kind
The kind of change the delivery tells about: one of the four above.
payload
The change's own facts as flat entries. A key carries 1 to 64 characters of letters, digits, underscore, dot and hyphen. A value is a string of up to 512 characters, a finite number, a boolean or null. At most 32 entries.

Each kind names the payload it carries, as flat entries:

Tier change payload
{
  "asOf": "2026-10-08T12:00:00.000Z",
  "credentialId": "crd_01J9ZQ4V8W7X6Y5Z4A3B2C1D0E",
  "holderId": "hld_01J9ZQ4V8W7X6Y5Z4A3B2C1D0E",
  "previousTier": "Holder",
  "tier": "Steward"
}
Benefit unlock payload
{
  "benefitId": "bft_01J9ZQ5B7C8D9E0F1G2H3J4K5M",
  "tier": "Steward"
}
Claim confirmation payload
{
  "claimId": "clm_01J9ZQ6N8P9Q0R1S2T3V4W5X6Y",
  "benefitId": "bft_01J9ZQ5B7C8D9E0F1G2H3J4K5M"
}
Redemption record payload
{
  "redemptionId": "red_01J9ZQ7P9R0S1T2V3W4X5Y6Z8A",
  "claimId": "clm_01J9ZQ6N8P9Q0R1S2T3V4W5X6Y"
}

Delivery rules

How a delivery reaches an endpoint:

At least once
A distributor may receive the same change more than once: a retry after an answer that was slow, or a redelivery. Yutai never promises exactly once.
One delivery per change
A redelivered change is the same delivery: Yutai keeps one delivery per change and endpoint, so a repeat answers the same delivery with the same payload. Record the event ids you have processed and answer a repeat without acting on it again.
No order promised
Changes can arrive in any order, and a later change can arrive before an earlier one after a retry. A distributor that needs the current state reads it from Yutai with the calls the API reference names rather than replaying deliveries in arrival order.

Retries

Each attempt answers delivered or failed: a failed answer carries the reason it failed, a delivered one carries none. A failed attempt is tried again on the schedule below; a delivered one ends the delivery.

Attempt 1
when the change is sent
Attempt 2
1 minute later
Attempt 3
5 minutes later
Attempt 4
30 minutes later
Attempt 5
2 hours later

A delivery that has spent its 5 attempts stays failed and is not tried again on its own. Once it is, Yutai's team can send it again by hand, at most 3 times, each named beside the operator who pressed it.

The signature

A receiver checks a delivery's signature in the Yutai-Signature header. The value carries two parts joined by a comma: t is the whole number of unix seconds the delivery was signed at, and v1 is the signature itself, 64 lowercase hex characters. For example Yutai-Signature: t=1781000000,v1=3f9a1c7e5b2d8f04a6c1e9d3b7f5a2c8e4d6b0f2a8c6e1d3f5a7b9c0e2d4f6a8.

A receiver checks the timestamp first: only a header whose t sits within 300 seconds of the receiver's own clock, either way, is fresh, so a captured delivery cannot be replayed later and pass. The signature binds the delivery's own facts, the one message:

The message the signature binds
Yutai webhook delivery
Tenant: tnt_01J9ZQ4V8W7X6Y5Z4A3B2C1D0E
Event: tier-update-1
Kind: tier_changed
Endpoint: https://hooks.example.test/yutai
Payload: {"asOf":"2026-10-08T12:00:00.000Z","credentialId":"crd_01J9ZQ4V8W7X6Y5Z4A3B2C1D0E","holderId":"hld_01J9ZQ4V8W7X6Y5Z4A3B2C1D0E","previousTier":"Holder","tier":"Steward"}

The real signing key is not issued yet. Until it is, the signature a stored delivery carries is the simulated digest proof over the same message, not the header above.