member.suspended
Merchant-level suspension state changed; suspension and restoration share this event
When Emitted
Emitted after POST /v1/members/{id}/suspend actually changes merchant_status.
Restoration emits the same event, with status: normal; status identifies the direction.
A separate restoration event would require examining two event streams to answer whether the member can currently use the service.
This flag only controls availability for the member under your merchant. Platform-level blocking is separate and not visible to you.
⚠ status_version is always 0, and this event can recur: suspend → restore → suspend again.
This is therefore the one place among these events where ordering by created_at is genuinely necessary.
Do not skip equal versions, or the restoration event will be discarded and the member will remain blocked on your side.
Payload
{
"event_id": "evt_7c93a1d05e6b4a2f9d81c4e0f2a37b56",
"event_type": "member.suspended",
"created_at": "2026-08-12T10:02:11Z",
"merchant_id": "acme",
"livemode": true,
"data": {
"object": "member",
"id": "4b7c1e02-9a3d-4f18-8c55-2d61ab0f9e77",
"external_member_id": "u_88123",
"status": "suspended",
"status_version": 0
}
}
Payload Fields
| Field | Type | Description |
|---|---|---|
id | string | Use this for deduplication. evt_… remains unchanged when the same event is redelivered. |
type | string | Always member.suspended |
created_at | string | Time the event was created (RFC3339), not its delivery time. It is unchanged on redelivery. |
data.object | string | Object type; determines which endpoint to query with data.id |
data.id | string | Object ID; use it to retrieve details. |
data.status | string | Treat unrecognized values as unknown and raise an alert; do not fall back to “processing” |
data.status_version | number | Monotonically increasing; use it to discard older states that arrive late. |
Signature Verification and Deduplication
Verify the signature against the raw request body bytes. Do not parse and reserialize the JSON: your JSON library may change key order or whitespace, which changes the signature and can look like a key configuration error.
// Node · Run before parsing JSON
const raw = await readRawBody(req); // Buffer / string; do not use parsed req.body
const expect = crypto.createHmac("sha256", WEBHOOK_SECRET).update(raw).digest("hex");
const got = req.headers["z-signature"]; // Format: t=<unix>,v1=<hex>
if (!timingSafeEqual(expect, parseV1(got))) return res.status(400).end();
// Deduplicate using the envelope id, not data.id
if (await seen(JSON.parse(raw).id)) return res.status(200).end();
For the full procedure, including timestamp tolerance and redelivery semantics, see Webhook Guide.