Foreshock

Concepts

The signal lifecycle

Three live stages, three terminal ones, and the two terminal states that are most often misread as an all-clear.

Updated
2026-08-24

A match between an enforcement event and one of your addresses has a stage. The stage is what the caller acts on.

The live stages

Reported as stage on every match, and in the exposure.match webhook.

StageWhat it means to a caller
PROPOSEDThe event exists and has not been executed. Treat as live and begin declining inbound funds on the matched address.
CONFIRMINGThe event is progressing toward execution.
EXECUTEDThe event has been carried out.

PROPOSED is not a rumour and it is not a prediction. It is an observation of something that exists on-chain. What it does not carry is any promise about how long you have: the interval between a proposal and its execution is a by-product of the issuer’s governance structure, not a service Foreshock provides, and an issuer can change how it executes at any time. Build the workflow so that it is correct when the interval is zero.

The terminal stages

A match that leaves the active set is announced through the exposure.revoked webhook with a RevocationStage, and disappears from subsequent pages of GET /v1/exposure.

StageWhat it means
REVOKEDThe underlying event was withdrawn.
EXPIREDThe event did not execute within its configured window.
STALEThe underlying data can no longer be trusted.

REVOKED is not a clearance

A revocation states one thing: the match is no longer in your active match set. It does not state that the address is safe. A withdrawn event can be re-raised.

Removals are always announced as their own event and are never silent. That is deliberate, and it is the reason the webhook exists at all: if removals were silent, your local list would diverge from ours and you would not know. Handle exposure.revoked as a state change to record, not as permission to release funds you were holding for other reasons.

STALE is not safe

STALE means the data behind the match can no longer be trusted — not that the risk went away. Treat the affected scope as a blind spot, not as an all-clear, and fall back to a more conservative policy until it clears.

The same reading applies wherever the word appears. LIST_STALE and REGISTRY_ENTRY_STALE are degradation reason codes on the decision path, and both produce HOLD. A stale input never produces a CREDIT.

Reconciliation is the feed, not the webhook

Webhook delivery is at-least-once, and a delivery can fail for 24 hours before it lands in a dead-letter queue. An event you did not receive is not an event that did not happen.

GET /v1/exposure with your last cursor is the authoritative reconciliation path. Run it on a schedule regardless of webhook health, and run it after any period where your receiver was down.