Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.hitpayapp.com/llms.txt

Use this file to discover all available pages before exploring further.

Overview

HitPay provides event webhooks that are HTTP post requests triggered after key events that happen on the hitpay platform. These webhooks can be used to build your own automation and processes.

List of Events

These are the list of events you can listen to
Event NameWhen does it trigger?
charge.createdOnce a payment is successfully completed
charge.updatedOnce a payment is refunded / partially refunded
payout.createdOnce a payout is successfully completed
order.createdOnce an order is created successfully
order.updatedOnce an order status is updated
invoice.createdOnce the invoice is created
transfer.createdOnce the transfer is created
transfer.updatedOnce the transfer is updated
transfer.processingOnce the transfer is processed
transfer.scheduledOnce the transfer is scheduled
transfer.paidOnce the transfer is paid
transfer.failedOnce the transfer is failed
transfer.canceledOnce the transfer is canceled
payment_request.completedOnce the payment request has been paid
payment_request.failedOnce the payment request received an error
recurring_billing.method_attachedOnce a payment method is attached to a subscription
recurring_billing.method_detachedOnce a payment method (APMs) is detached from a subscription
recurring_billing.subscription_updatedOnce a subscription is updated, including status changes (active, cancelled, paused, expired) and edits made via the dashboard

Register Your Webhook

The first thing you need to do before you can receive the webhook is to register the URL. Navigate to “API Keys” and enter the name and the URL you wish to receive the webhook.
Hero Dark

Webhook Payload

Headers that are included in the webhook HTTP POST request
HTTP headerdetails
Hitpay-SignatureHMAC-SHA256 of the raw JSON body, using that webhook endpoint’s salt
Hitpay-Event-Typecreated / updated based on the event
Hitpay-Event-ObjectThe type of object. It can be charge/payout/invoice/order/transfer
User-AgentHitPay v2.0
HTTP request body is a JSON object and the object structure can be any of the above 5 types. Refer to the header value Hitpay-Event-Objectto determine the object type of webhooks for charge payout invoice order transfer

Event examples for charge invoice order

{
  "id": "9e9a3451-a3e5-4fc5-9dfc-bc75e67c8808",
  "business_id": "98567029-f559-49f9-916b-042a4255b32a",
  "channel": "point_of_sale",
  "customer_id": "9b3503bd-fd04-4e39-9271-b2bc26fa5c96",
  "status": "succeeded",
  "customer": {
    "name": "Miss Vincent Marquardt",
    "email": "test@gmail.com",
    "phone_number": "666",
    "address": {
      "street": null,
      "city": null,
      "state": null,
      "postal_code": null,
      "country": null
    }
  },
  "currency": "sgd",
  "amount": 913.84,
  "refunded_amount": 0,
  "refunded_at": null,
  "fixed_fee": 0,
  "discount_fee": 0,
  "discount_fee_rate": 0,
  "failed_reason": null,
  "order": {
    "id": "9e9a344b-2c04-44f4-b521-e36dce8f4ade",
    "order_display_number": 2766,
    "business_id": "98567029-f559-49f9-916b-042a4255b32a",
    "channel": "point_of_sale",
    "version": "2.0",
    "customer_id": "9b3503bd-fd04-4e39-9271-b2bc26fa5c96",
    "business_customer_id": "9b3503bd-fd04-4e39-9271-b2bc26fa5c96",
    "customer": {
      "name": "Miss Vincent Marquardt",
      "email": "test@gmail.com",
      "phone_number": "666",
      "address": {
        "street": null,
        "building": null,
        "street_2": null,
        "city": null,
        "state": null,
        "postal_code": null,
        "country": null
      }
    },
    "customer_pickup": false,
    "currency": "sgd",
    "order_discount_name": null,
    "status": "completed",
    "remark": null,
    "created_at": "2025-04-05T19:09:54+08:00",
    "updated_at": "2025-04-05T19:09:59+08:00",
    "closed_at": "2025-04-05T19:09:59+08:00",
    "location_id": "9e42e6be-2ff8-4b37-ac14-07970d2e79ca",
    "location": null,
    "business_user_id": "1306",
    "slot_date": null,
    "slot_time": null,
    "messages": null,
    "products": [],
    "charges": [],
    "line_items": [
      {
        "id": "9e9a344c-7b3c-4330-8926-0f9df43c3b08",
        "name": "POS TESTING - BLue",
        "thumbnail": null,
        "item_type": "product",
        "quantity": 1,
        "related_id": "9e4b75c4-cce6-4f08-ab71-abf8907f41a4",
        "unit_price": 913.84,
        "line_item_amount": 913.84,
        "item_unit_weight": 883,
        "params": null,
        "children": []
      }
    ],
    "order_form_response": null,
    "coupon": null,
    "pickup": null,
    "payment_status": "paid",
    "fulfilment_status": "completed",
    "fulfilment_type": "in_store",
    "line_items_total": 913.84,
    "order_discount_amount": 0,
    "line_item_discount_amount": 0,
    "line_item_tax_amount": 0,
    "additional_discount_amount": 0,
    "total_discount_amount": 0,
    "line_item_price": 913.84,
    "shipping_amount": 0,
    "total_coupon_amount": 0,
    "amount": 913.84,
    "subtotal": 913.84
  },
  "order_id": "9e9a344b-2c04-44f4-b521-e36dce8f4ade",
  "remark": null,
  "payment_intents": [],
  "payment_request_id": null,
  "payment_request": null,
  "all_inclusive_fee": null,
  "home_currency": null,
  "payment_provider": {
    "code": "hitpay",
    "account_id": "98567029-f559-49f9-916b-042a4255b32a",
    "charge": {
      "type": "business_charge",
      "id": "9e9a3451-a3e5-4fc5-9dfc-bc75e67c8808",
      "method": "cash",
      "transfer_type": null,
      "details": null,
      "logo": "/icons/payment-methods-2/cash.png"
    }
  },
  "created_at": "2025-04-05T19:09:59+08:00",
  "updated_at": "2025-04-05T19:10:01+08:00",
  "closed_at": "2025-04-05T19:09:59+08:00",
  "location_id": "9e42e6be-2ff8-4b37-ac14-07970d2e79ca",
  "location": {
    "id": "9e42e6be-2ff8-4b37-ac14-07970d2e79ca",
    "name": "API_Location_1740101762910",
    "address": "58 Izpod Parkway, Singapore, Singapore, sg, 079903"
  },
  "business_user_id": "1306",
  "business_user_display": "TestingSG",
  "terminal_id": null,
  "relatable": null
}

Event examples for payout transfer

{
  "id": "9e9be893-9fee-4916-aca0-403e8e42b99e",
  "beneficiary": {
    "id": "9e25698b-6792-4ec6-aa81-f58692674171",
    "is_external": true,
    "status": "approved",
    "country": "sg",
    "currency": "sgd",
    "wallet_provider": "hitpay",
    "wallet_capability": "beneficiary",
    "transfer_method": "local",
    "nickname": null,
    "remark": null,
    "holder_name": "HONGKONG & SHANGHAI BANKING CORPORATION (HSBC)",
    "holder_type": "company",
    "bank_branch_code": "040",
    "account_number": "000123454",
    "bank_name": "MALAYAN BANKING BERHAD",
    "bank_id": "MBBESGS2[9636]",
    "email": "test@gmail.com",
    "is_favourite": true,
    "created_at": "2025-02-06T17:46:57+08:00",
    "updated_at": "2025-03-22T22:42:17+08:00",
    "deleted_at": null
  },
  "payment_currency": "sgd",
  "payment_amount": 100,
  "source_currency": "sgd",
  "source_amount": 100,
  "exchange_rate": "1.00000",
  "fee_payer": "payer",
  "discount_fee_rate": 0,
  "fixed_fee": 0,
  "discount_fee": 0,
  "total_fee": 0,
  "fee_currency": "sgd",
  "remark": "123457788",
  "status": "scheduled",
  "attachment": null,
  "created_at": "2025-04-06T15:29:51+08:00"
}
Note: List of failure codes for transfer.failed event
CodeDescription
100101Invalid account number
100102Invalid bank branch code
100103Invalid SWIFT/BIC code
100104Invalid correspondent bank information
100105Invalid bank information
100106Invalid proxy details
100107Transaction not supported
100108Account type not supported
100201Beneficiary name mismatch
100202Account currency mismatch
100301Invalid beneficiary details
100302Invalid special character in beneficiary details
100303Invalid beneficiary country
100401Screening error
100402Regulatory restriction
100501Insufficient balance
100601Account closed
100602Account inactive or dormant
100603Account under restriction
100604Beneficiary deceased
100701Beneficiary requested
100702Beneficiary bank returned
100801China local transfer beneficiary validation error
100802China local transfer order error
100803Beneficiary account type not supported
100804China company registration number error
100805China local transfer processing failure
100901Recall requested
100902Client requested
101001Invalid payment purpose
101002Wrong amount
101003Amount exceeds limit
101101System error
101102Channel timeout
101103Bank offline
101201Other error
101202Duplicate payment

Event examples for payment_request

{
  "id": "9e9be893-9fee-4916-aca0-403e8e42b99e",
  "bank_name": "MALAYAN BANKING BERHAD",
  "bank_swift_code": "MBBESGS2XXX",
  "bank_account_number": "000123454",
  "currency": "sgd",
  "amount": 100,
  "status": "succeeded",
  "created_at": "2025-04-06T15:29:51+08:00"
}

Validating Webhook

HitPay uses two different salt values depending on the integration. Use the right one for the callback you are handling.

API-key salt (Developers page)

This salt belongs to your business API key and is shown on the Developers page alongside your API key. It signs older payment-request and charge callbacks, plus plugin integrations—the API-driven payment flow where an hmac value is returned with the payment status. Used for:
  • Payment Request webhook and redirect callbacks
  • Recurring payment callbacks
  • Order and checkout callbacks (Shop, Order webhook, Hardware order)
  • Plugin HMAC validation (Shopify, Wix, Xero)
How it works: Sort and concatenate the callback parameters, then compute HMAC-SHA256 using the API-key salt. The signature is sent in the hmac field in the payload, not in a header.

Per-webhook salt (Developers → Webhooks)

Each webhook endpoint you register under Developers → Webhooks has its own salt. This is the salt for event webhooks on this page (for example charge.completed, order.updated). How it works: Compute HMAC-SHA256 of the raw request body using that webhook’s salt. The signature is sent in the Hitpay-Signature header. Find the salt on the webhook’s detail view in the dashboard after you create the webhook endpoint.

The differences

API-key saltPer-webhook salt
ScopeOne per business API keyOne per webhook endpoint
Used forPayment-request, charge, and plugin callbacksEvent webhooks
Signature inhmac field in the payloadHitpay-Signature header
What’s signedSorted and concatenated parametersRaw JSON body
The steps below apply to event webhooks and use the per-webhook salt.

Validate Hitpay-Signature

  1. Collect data: Read the raw JSON body and the Hitpay-Signature header from the incoming request.
  2. Prepare key: Use the salt for that webhook endpoint (from Developers → Webhooks), not the API-key salt on the main Developers page.
  3. Compute HMAC: Generate HMAC-SHA256 over the raw body bytes with that webhook’s salt as the key.
  4. Compare signatures: Compare the computed HMAC to Hitpay-Signature. If they match, the request is authentic and unmodified.
function validateWebhook($payload, $signature, $salt) {
    $computedSignature = hash_hmac('sha256', $payload, $salt);
    return hash_equals($computedSignature, $signature);
}

// Usage
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_HITPAY_SIGNATURE'];
$salt = 'your_webhook_salt_from_dashboard';

if (validateWebhook($payload, $signature, $salt)) {
    $data = json_decode($payload, true);
// Process the event
} else {
http_response_code(401);
exit('Invalid signature');
}

Last modified on June 2, 2026