webhook

Kyshi webhooks send real-time HTTP POST notifications to your configured webhook URL when important events happen on your account, such as successful or failed charges, virtual account payments, invoice events, and subscription lifecycle updates.

Webhooks are sent as JSON and include signature headers so you can verify that the request came from Kyshi.

Setup

Configure your webhook URLs from your business settings in your merchant dashboard:

FieldDescription
Test WebhookWebhook URL used for test-mode transactions and events
Live WebhookWebhook URL used for live-mode transactions and events

Webhook Endpoint Requirements

Your webhook endpoint must:

  • Accept POST requests
  • Accept Content-Type: application/json
  • Respond with a 2xx HTTP status when the webhook is processed successfully
  • Respond within 10 seconds
  • Be publicly reachable over HTTPS

Webhook Headers

Every webhook request includes these headers:

HeaderDescription
Content-TypeAlways application/json
User-AgentKyshi-Webhook/1.0
X-Kyshi-Event-IDUnique ID for the webhook delivery attempt
X-Kyshi-SignatureHMAC-SHA256 signature of the webhook payload
X-Kyshi-TimestampUnix timestamp in milliseconds when the webhook was sent

Validating Webhooks

Kyshi signs each webhook using HMAC-SHA256.

To Validate a Webhook

  1. Get the raw JSON request body.
  2. Create an HMAC-SHA256 hash using your mode-specific Kyshi signing secret/API key reference.
  3. Compare your generated hash with the X-Kyshi-Signature header.
  4. Process the webhook only if both signatures match.

Important Note

  • Use your test configuration for test-mode webhooks.
  • Use your live configuration for live-mode webhooks.
  • Process webhooks idempotently; the same business event may be delivered more than once.
  • Verify high-value state changes with the API before giving value.

Retry Behavior

Kyshi considers a webhook delivered when your endpoint returns any 2xx status code.

If your endpoint returns a 5xx response or the request fails due to a network error, Kyshi retries up to 3 times

4xx responses are treated as failed delivery attempts and are not automatically retried.


Events

EventDescription
charge.successA charge or virtual account collection was successful
charge.failedA charge or virtual account collection failed
invoice.createdA subscription invoice was created
invoice.updatedA subscription invoice was updated
invoice.payment_succeededA subscription invoice payment succeeded
invoice.payment_failedA subscription invoice payment failed
subscription.activeA subscription became active
subscription.past_dueA subscription moved to past due
subscription.cancelledA subscription was cancelled
subscription.not_renewingA subscription will not renew at period end
subscription.completedA subscription completed its invoice/payment limit

Charge Webhook Payload

{
  "reference": "KYSHI-123456789",
  "amount": 10000,
  "customer": {
    "id": "customer-id",
    "first_name": "Ada",
    "last_name": "Lovelace",
    "email": "[email protected]",
    "phone": "+2348012345678"
  },
  "originator": null,
  "authorization": {
    "authorization_code": "AUTH_abc123",
    "bin": "408408",
    "last4": "4081",
    "exp_month": "12",
    "exp_year": "2030",
    "channel": "card",
    "card_type": "visa",
    "bank": "Test Bank",
    "country_code": "NG",
    "brand": "visa",
    "reusable": true
  },
  "log": {},
  "meta": {
    "localCurrency": "NGN",
    "localAmount": 10000,
    "fxRate": 1500,
    "settlementAmount": 6.67,
    "settlementCurrency": "USD",
    "settlementSymbol": "$",
    "netAmount": 9750,
    "feeBearer": "CUSTOMER",
    "taxChargeable": "EXCLUSIVE",
    "mode": "live",
    "transactionId": "transaction-id",
    "providerStatus": "success",
    "kyshiEventId": "event-id",
    "kyshiWebhookSentAt": "2026-05-08T12:00:00.000Z",
    "feeBreakdown": {
      "vat": 10,
      "fee": 200,
      "allInclusiveKyshiFee": 200,
      "processorFee": 50,
      "stampDuty": 0,
      "others": {},
      "totalFees": 260
    }
  },
  "event": "charge.success",
  "status": "success"
}

 

Important Fields

FieldDescription
eventWebhook event name, for example charge.success
statusEvent status, usually success or failed
referenceUnique transaction reference
amountTotal local amount charged/collected
customerCustomer details
originatorOriginator details for virtual account/bank transfer payments, when available
authorizationPayment authorization details
logProvider/API activity log
meta.localCurrencyLocal collection currency
meta.localAmountLocal amount collected
meta.fxRateFX rate used, when applicable
meta.settlementAmountSettlement amount, when applicable
meta.settlementCurrencySettlement currency, when applicable
meta.netAmountAmount after fees
meta.feeBearerParty responsible for fees
meta.taxChargeableTax charging mode
meta.modetest or live
meta.transactionIdKyshi transaction ID
meta.kyshiEventIdKyshi webhook event ID
meta.kyshiWebhookSentAtTimestamp when the webhook was sent
meta.feeBreakdownDetailed fee breakdown

Best Practices

  • Verify every webhook signature before processing.
  • Use reference or meta.transactionId for idempotency.
  • Return 2xx only after your system has safely accepted the webhook.
  • Do not rely only on X-Kyshi-Event-ID for transaction deduplication because retry attempts may have different delivery IDs.
  • Log failed signature checks and return a non-2xx response for invalid webhooks.