Z Zise Developers 简体中文

earn.order.settled

Earn proceeds credited: flexible interest payments / fixed-term principal and interest at maturity

When Emitted

Two different operations share this event: · Flexible interest payment: after each interest posting, data.id is the internal member ID, with status_version always 0; flexible Earn uses a balance pool, not one order per transaction. · Fixed-term maturity settlement: after principal and interest settle, data.id is the fixed-term order ID and includes status_version. To distinguish them, look for data.id in GET /v1/earn/orders. A match indicates fixed-term settlement; no match indicates a flexible interest payment, for which GET /v1/earn/positions shows the flexible principal. ⚠ No event is sent when fixed-term interest starts accruing. You or the member initiated the subscription, so there is no new information.

Payload

{
  "event_id": "evt_9e04b7c2513f486da8021c6e5f7b3d90",
  "event_type": "earn.order.settled",
  "created_at": "2026-08-13T00:05:00Z",
  "merchant_id": "acme",
  "livemode": true,
  "data": {
    "object": "earn_order",
    "id": "b52c8e17-3d94-40af-8617-c9e0d21a4f35",
    "external_member_id": "u_88123",
    "status": "settled",
    "status_version": 2
  }
}

Payload Fields

FieldTypeDescription
idstringUse this for deduplication. evt_… remains unchanged when the same event is redelivered.
typestringAlways earn.order.settled
created_atstringTime the event was created (RFC3339), not its delivery time. It is unchanged on redelivery.
data.objectstringObject type; determines which endpoint to query with data.id
data.idstringObject ID; use it to retrieve details.
data.statusstringTreat unrecognized values as unknown and raise an alert; do not fall back to “processing”
data.status_versionnumberMonotonically 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.