NewDash Dots are hereMini apps in Dash, with payments built inLearn more

Developer Resources · Webhooks

Events and Payloads

When Monime sends a webhook delivery, the request body contains a JSON payload describing the event. This page documents the payload structure, explains the naming conventions, and provides sample payloads for each event type.

Understanding the payload envelope

Every webhook payload follows the same envelope structure. The envelope contains metadata about the event and API version, while the data field holds the resource-specific content.

JSON
{
  "apiVersion": "caph.2025-08-23",
  "event": {
    "id": "wke-7b3f2f1b5c1e4a",
    "name": "payment_code.processed",
    "timestamp": "1760201200"
  },
  "object": {
    "id": "pmc-9xY7r1",
    "type": "payment_code"
  },
  "data": {
    "id": "pmc-9xY7r1"
  }
}

This consistent structure makes it easy to write generic handling code. Your handler can extract event metadata the same way regardless of event type, then dispatch to specialized logic based on event.name.

Envelope fields explained

The apiVersion field indicates which API release generated this payload. The release determines the available event types and the structure of the data field. When you create a webhook, you select an API release, and all deliveries use that release's schema.

The event object contains metadata about the event itself:

  • id is a unique identifier for this specific event occurrence. Use this ID for idempotency—if you receive the same event ID twice, you can skip reprocessing. Event IDs are prefixed with wke- followed by a random string.
  • name identifies what happened. Event names follow the pattern resource.action, such as payment.processing_completed or checkout_session.expired. The name tells you which handler to invoke.
  • timestamp is a Unix timestamp (seconds since epoch) indicating when the event occurred. This is the time the event happened in Monime's system, not the time the delivery was sent.

The object field identifies the resource that triggered the event:

  • id is the resource's unique identifier. You can use this ID to fetch the full resource from the Monime API if you need more data than the payload provides.
  • type indicates the resource type, such as payment_code, payment, checkout_session, or payout.

The data field contains a representation of the resource at the time of the event. The structure varies by resource type and often by event type within a resource. For example, a payment_code.processed event includes payment details, while a payment_code.cancelled event may include only the ID and status.

Event naming conventions

Event names use the format resource.action, where the resource is the type of object involved and the action describes what happened to it.

Resources correspond to Monime objects such as payment_code, payment, checkout_session, payout, financial_account, financial_transaction, internal_transfer, and ussd_otp. Actions describe lifecycle changes such as created, processing_started, processing_completed, credited, debited, completed, failed, expired, verified, and cancelled.

When your handler receives an event, parse the name to determine routing:

JavaScript
function handleWebhook(payload) {
  const [resource, action] = payload.event.name.split('.');

  switch (resource) {
    case 'payment':
      return handlePaymentEvent(action, payload);
    case 'payout':
      return handlePayoutEvent(action, payload);
    // ...
  }
}

Current release event registry

The webhook release determines which event names you can select. Caph is the latest release. SiriusB uses the 2024-08-01 release identifier.

  • checkout_session.cancelled
  • checkout_session.completed
  • checkout_session.expired
  • financial_account.created
  • financial_account.credited
  • financial_account.debited
  • financial_transaction.created
  • internal_transfer.completed
  • internal_transfer.created
  • internal_transfer.failed
  • payment.created
  • payment.processing_completed
  • payment.processing_started
  • payment_code.cancelled
  • payment_code.completed
  • payment_code.expired
  • payment_code.processed
  • payout.completed
  • payout.failed
  • ussd_otp.expired
  • ussd_otp.verified
  • payment_code.completed
  • payment_code.created
  • payment_code.expired
  • payment_code.processed
  • payout.completed
  • payout.created
  • payout.delayed
  • payout.failed
  • payout.processed
  • payout.reversed

The payload examples below retain the authoritative envelope and data shapes from the imported webhook documentation branch. Each example is labelled with an event and release from the current registry.

Payment code events

Payment codes are merchant-generated codes that customers use to initiate payments, often through USSD. Events track the payment code lifecycle from creation through completion, expiration, or cancellation.

Caph includes payment_code.processed, payment_code.completed, payment_code.expired, and payment_code.cancelled. SiriusB includes payment_code.created, payment_code.processed, payment_code.completed, and payment_code.expired.

For full field definitions, see the Payment Code object reference.

Fired when a new payment code is created. The payload contains the complete payment code configuration including amount, expiration time, authorized providers, and metadata.

JSON
{
  "apiVersion": "2024-08-01",
  "event": {
    "id": "wke-21a1c2f0b7e146",
    "name": "payment_code.created",
    "timestamp": "1760201200"
  },
  "object": {
    "id": "pmc-9xY7r1",
    "type": "payment_code"
  },
  "data": {
    "id": "pmc-9xY7r1",
    "mode": "one_time",
    "status": "pending",
    "name": "Home EDSA Meter Top-up",
    "amount": {
      "currency": "SLE",
      "value": 10000
    },
    "enable": true,
    "expireTime": "2026-02-05T13:45:00Z",
    "ussdCode": "*715*1*7344331308#",
    "authorizedProviders": ["m17", "m18"],
    "financialAccountId": "fac-4nS8kF",
    "createTime": "2026-02-05T13:30:00Z",
    "metadata": {
      "order_id": "ord_123"
    }
  }
}

Fired when a payment is received against the code but not yet completed. The processedPaymentData field contains details about the incoming payment, including the payment ID and channel information.

JSON
{
  "apiVersion": "caph.2025-08-23",
  "event": {
    "id": "wke-4f8c3c2a9a401a",
    "name": "payment_code.processed",
    "timestamp": "1760201502"
  },
  "object": {
    "id": "pmc-9xY7r1",
    "type": "payment_code"
  },
  "data": {
    "id": "pmc-9xY7r1",
    "mode": "one_time",
    "status": "processing",
    "amount": {
      "currency": "SLE",
      "value": 10000
    },
    "processedPaymentData": {
      "amount": {
        "currency": "SLE",
        "value": 10000
      },
      "orderId": "ord-8Hk2f",
      "paymentId": "pay-2b8Xk",
      "orderNumber": "808956084535",
      "channelData": {
        "providerId": "m17",
        "accountId": "23278341807",
        "reference": "MP240830.1142.B79174"
      },
      "financialTransactionReference": "ftx-0u3fA"
    },
    "updateTime": "2026-02-05T13:31:10Z"
  }
}

Fired when the payment code reaches its terminal successful state. For one-time codes, this means the expected payment was received and confirmed. The payload contains the final status.

JSON
{
  "apiVersion": "caph.2025-08-23",
  "event": {
    "id": "wke-6b04d7e1a1f71c",
    "name": "payment_code.completed",
    "timestamp": "1760201800"
  },
  "object": {
    "id": "pmc-9xY7r1",
    "type": "payment_code"
  },
  "data": {
    "id": "pmc-9xY7r1",
    "mode": "one_time",
    "status": "completed",
    "amount": {
      "currency": "SLE",
      "value": 10000
    },
    "enable": true,
    "updateTime": "2026-02-05T13:36:40Z"
  }
}

Fired when a payment code passes its expireTime without being used. The status is now expired, and the code can no longer accept payments.

JSON
{
  "apiVersion": "caph.2025-08-23",
  "event": {
    "id": "wke-58cf2b0a9d1c43",
    "name": "payment_code.expired",
    "timestamp": "1760205200"
  },
  "object": {
    "id": "pmc-9xY7r1",
    "type": "payment_code"
  },
  "data": {
    "id": "pmc-9xY7r1",
    "mode": "one_time",
    "status": "expired",
    "expireTime": "2026-02-05T13:45:00Z",
    "updateTime": "2026-02-05T13:45:00Z"
  }
}

Fired when a payment code is cancelled via the API or dashboard. Cancelled codes cannot accept payments.

JSON
{
  "apiVersion": "caph.2025-08-23",
  "event": {
    "id": "wke-2a6b8ad91cfe4e",
    "name": "payment_code.cancelled",
    "timestamp": "1760202100"
  },
  "object": {
    "id": "pmc-9xY7r1",
    "type": "payment_code"
  },
  "data": {
    "id": "pmc-9xY7r1",
    "mode": "one_time",
    "status": "cancelled",
    "updateTime": "2026-02-05T13:35:00Z"
  }
}

Payment events

Payment events track individual payments as they move through processing. These are distinct from payment codes—a payment code might generate a payment, but the payment has its own lifecycle.

Caph includes payment.created, payment.processing_started, and payment.processing_completed.

For full field definitions, see the Payment object reference.

Fired when a new payment is created. The payment starts in pending status. The payload includes the amount, channel type, and order number.

JSON
{
  "apiVersion": "caph.2025-08-23",
  "event": {
    "id": "wke-0c8f1b2d3e4f5a",
    "name": "payment.created",
    "timestamp": "1760201200"
  },
  "object": {
    "id": "pay-4kL2n",
    "type": "payment"
  },
  "data": {
    "id": "pay-4kL2n",
    "status": "pending",
    "amount": {
      "currency": "SLE",
      "value": 5000
    },
    "channel": {
      "type": "momo"
    },
    "orderNumber": "901234567890",
    "createTime": "2026-02-05T13:30:00Z"
  }
}

Fired when the payment enters processing. This indicates the payment channel is actively working on the transaction. The status transitions from pending to processing.

JSON
{
  "apiVersion": "caph.2025-08-23",
  "event": {
    "id": "wke-3a4b5c6d7e8f90",
    "name": "payment.processing_started",
    "timestamp": "1760201250"
  },
  "object": {
    "id": "pay-4kL2n",
    "type": "payment"
  },
  "data": {
    "id": "pay-4kL2n",
    "status": "processing",
    "amount": {
      "currency": "SLE",
      "value": 5000
    },
    "channel": {
      "type": "momo"
    },
    "updateTime": "2026-02-05T13:30:50Z"
  }
}

Fired when the payment completes successfully. Funds have been transferred and the transaction is confirmed. The financialTransactionReference links to the underlying financial transaction.

JSON
{
  "apiVersion": "caph.2025-08-23",
  "event": {
    "id": "wke-9f8e7d6c5b4a32",
    "name": "payment.processing_completed",
    "timestamp": "1760201400"
  },
  "object": {
    "id": "pay-4kL2n",
    "type": "payment"
  },
  "data": {
    "id": "pay-4kL2n",
    "status": "completed",
    "amount": {
      "currency": "SLE",
      "value": 5000
    },
    "channel": {
      "type": "momo"
    },
    "financialTransactionReference": "ftx-2a9kQ",
    "updateTime": "2026-02-05T13:32:10Z"
  }
}

Checkout session events

Checkout sessions represent customer-facing payment flows, typically rendered through Monime's hosted checkout page. Events track whether the customer completed the checkout, cancelled it, or let it expire.

Available events:

  • checkout_session.completed — The customer completed the checkout and payment succeeded
  • checkout_session.cancelled — The customer cancelled the checkout
  • checkout_session.expired — The checkout session expired before completion

For full field definitions, see the Checkout Session object reference.

Fired when a checkout session completes successfully. The customer has paid, and you should fulfill their order. The orderNumber helps you match this to your internal records.

JSON
{
  "apiVersion": "caph.2025-08-23",
  "event": {
    "id": "wke-5c4b3a2d1e0f9a",
    "name": "checkout_session.completed",
    "timestamp": "1760201600"
  },
  "object": {
    "id": "chk-6mN2p",
    "type": "checkout_session"
  },
  "data": {
    "id": "chk-6mN2p",
    "status": "completed",
    "orderNumber": "123456789012",
    "successUrl": "https://example.com/success",
    "createTime": "2026-02-05T13:20:00Z",
    "updateTime": "2026-02-05T13:33:10Z"
  }
}

Fired when the customer clicks cancel or navigates away. No payment was made. You might use this to release reserved inventory or send an abandoned cart reminder.

JSON
{
  "apiVersion": "caph.2025-08-23",
  "event": {
    "id": "wke-1a2b3c4d5e6f70",
    "name": "checkout_session.cancelled",
    "timestamp": "1760201550"
  },
  "object": {
    "id": "chk-6mN2p",
    "type": "checkout_session"
  },
  "data": {
    "id": "chk-6mN2p",
    "status": "cancelled",
    "cancelUrl": "https://example.com/cancel",
    "updateTime": "2026-02-05T13:32:30Z"
  }
}

Fired when a checkout session reaches its expiration time without being completed or cancelled. Sessions have a limited lifetime to prevent stale pricing or inventory issues.

JSON
{
  "apiVersion": "caph.2025-08-23",
  "event": {
    "id": "wke-7a8b9c0d1e2f34",
    "name": "checkout_session.expired",
    "timestamp": "1760205200"
  },
  "object": {
    "id": "chk-6mN2p",
    "type": "checkout_session"
  },
  "data": {
    "id": "chk-6mN2p",
    "status": "expired",
    "expireTime": "2026-02-05T13:45:00Z",
    "updateTime": "2026-02-05T13:45:00Z"
  }
}

Payout events

Payout events track disbursements from your Monime financial account to external destinations like mobile money accounts. Events indicate whether the payout is in progress, completed successfully, or failed.

Caph includes payout.completed and payout.failed. SiriusB includes payout.created, payout.processed, payout.delayed, payout.completed, payout.failed, and payout.reversed.

For full field definitions, see the Payout object reference.

Fired when the payout is successfully delivered to the recipient. The funds have arrived at the destination account.

JSON
{
  "apiVersion": "caph.2025-08-23",
  "event": {
    "id": "wke-9a8b7c6d5e4f32",
    "name": "payout.completed",
    "timestamp": "1760201900"
  },
  "object": {
    "id": "pyt-3mP1x",
    "type": "payout"
  },
  "data": {
    "id": "pyt-3mP1x",
    "status": "completed",
    "amount": {
      "currency": "SLE",
      "value": 20000
    },
    "destination": {
      "type": "momo"
    },
    "updateTime": "2026-02-05T13:38:40Z"
  }
}

Fired when a payout cannot be completed. The failureDetail field explains what went wrong—insufficient funds, invalid destination, network issues, etc. Depending on the failure reason, you may be able to retry.

JSON
{
  "apiVersion": "caph.2025-08-23",
  "event": {
    "id": "wke-2b3c4d5e6f7081",
    "name": "payout.failed",
    "timestamp": "1760202000"
  },
  "object": {
    "id": "pyt-3mP1x",
    "type": "payout"
  },
  "data": {
    "id": "pyt-3mP1x",
    "status": "failed",
    "amount": {
      "currency": "SLE",
      "value": 20000
    },
    "failureDetail": {
      "code": "fund_insufficient",
      "message": "Source account lacks sufficient funds."
    },
    "updateTime": "2026-02-05T13:40:10Z"
  }
}

Other Caph events

Caph also publishes these events:

  • financial_account.created
  • financial_account.credited
  • financial_account.debited
  • financial_transaction.created
  • internal_transfer.created
  • internal_transfer.completed
  • internal_transfer.failed
  • ussd_otp.expired
  • ussd_otp.verified

Use the object.id and object.type fields to identify the affected resource. The imported branch does not provide additional payload examples for these events, so this guide does not invent them.

Implementing idempotency

The same event can be delivered multiple times due to retries, replays, or network conditions. Use the event.id field to detect duplicates.

Before processing an event, check whether you have already processed an event with that ID. If so, return success without re-processing. This prevents duplicate side effects like sending the same notification twice or crediting an account multiple times.

JavaScript
async function handleWebhook(payload) {
  const eventId = payload.event.id;

  // Check if already processed
  if (await alreadyProcessed(eventId)) {
    return { status: 200 }; // Return success to stop retries
  }

  // Process the event
  await processEvent(payload);

  // Mark as processed
  await markProcessed(eventId);

  return { status: 200 };
}

Store processed event IDs in a database with a time-to-live. The TTL should exceed Monime's retry window (about 24 hours) but can be shorter if you also handle duplicates at the business logic layer.

Handling out-of-order delivery

Events are sent in the order they occur, but network conditions and retries can cause deliveries to arrive out of order. A payment.processing_completed event might arrive before payment.processing_started if the earlier delivery failed initially.

Your handlers should tolerate this. Options include:

  • Use the timestamp. The event.timestamp field indicates when the event occurred. If you receive an event older than what you have already processed for that resource, you can ignore it.
  • Fetch current state. Use the event as a trigger to fetch the resource's current state from the API, rather than relying solely on the payload.
  • Design for convergence. Structure your data model so that applying events in any order eventually produces the correct state.

Partial payloads

Event payloads include a snapshot of the resource at the time of the event, but not necessarily every field. Fields that have not changed or are not relevant to the event may be omitted.

If you need the complete resource, use the object.id to fetch it from the Monime API:

JavaScript
const resourceId = payload.object.id;
const resourceType = payload.object.type;

// Fetch full resource from API
const fullResource = await monime.get(`/${resourceType}s/${resourceId}`);

Content-Type

All webhook deliveries are sent with Content-Type: application/json. The body is UTF-8 encoded JSON. Configure your web framework to handle JSON payloads and preserve raw bytes for signature verification.

Keep reading