> For the complete documentation index, see [llms.txt](https://docs.tylt.money/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.tylt.money/introduction/tylt-crossramp-fiat-crypto-solutions/philippines-php/administration/webhook-for-administrators.md).

# Webhook for Administrators

Tylt provides a webhook mechanism for approved rail partners to receive real-time updates on the status of payment instances for both pay-ins and pay-outs. For the Philippines PHP rail, this webhook page applies to:

| Flow                       | Description                                                                                            |
| -------------------------- | ------------------------------------------------------------------------------------------------------ |
| QRPH Pay-In                | PHP pay-in transaction where the end user pays in PHP and the merchant receives USDT settlement value. |
| InstaPay / PESONet Pay-Out | PHP pay-out transaction where USDT value is used to initiate a PHP disbursement.                       |

Tylt sends webhook notifications whenever there is a status change in the transaction lifecycle. The lifecycle is tracked using `eventId`, which identifies the current state of the payment instance. The existing Tylt webhook page states that callbacks are sent on transaction status changes and that the lifecycle is tracked through `eventId`.&#x20;

***

### Setting Up the Webhook

The partner must provide Tylt with an HTTP POST endpoint that can receive JSON webhook payloads.

The webhook endpoint should be capable of:

1. Receiving JSON payloads from Tylt.
2. Verifying the authenticity of the webhook using HMAC-SHA256 signature validation.
3. Processing the transaction status update based on the `eventId`.
4. Returning an HTTP `200` response with `ok` in the response body.

Tylt signs each webhook payload using HMAC-SHA256 and sends the signature in the `X-TLP-SIGNATURE` header. The existing webhook page also specifies that the callback endpoint must validate the signature and acknowledge the webhook with HTTP 200 and body `"ok"`.&#x20;

***

### Webhook Header

| Header            | Description                                                                               |
| ----------------- | ----------------------------------------------------------------------------------------- |
| `X-TLP-SIGNATURE` | HMAC-SHA256 signature generated using the raw POST data and the partner’s API secret key. |

***

### Pay-In Lifecycle

For QRPH pay-ins, Tylt sends webhook updates as the pay-in instance moves through the payment lifecycle.

```
eventId 1 → Instance Created
eventId 2 → Order Created
eventId 3 → Payment Processing
eventId 4 → Payment Completed
```

Exception or unsuccessful states may include:

```
eventId 8  → Payment Failed
eventId 9  → Order Cancelled or Expired
eventId 10 → KYC Failed
```

The partner should use the `instanceId`, `merchantOrderId`, and `eventDetails.eventId` to identify and process the pay-in update.

***

### Pay-Out Lifecycle

For InstaPay / PESONet pay-outs, Tylt sends webhook updates as the pay-out instance moves through the payment lifecycle.

```
eventId 1 → Instance Created
eventId 2 → Order Created
eventId 3 → Payment Processing
eventId 4 → Payment Completed
```

Exception or unsuccessful states may include:

```
eventId 8  → Payment Failed
eventId 9  → Order Cancelled or Expired
eventId 10 → KYC Failed
```

The partner should use the `instanceId`, `merchantOrderId`, and `eventDetails.eventId` to identify and process the pay-out update.

***

### Validating Webhooks

Partners should validate the HMAC signature included in the `X-TLP-SIGNATURE` header to confirm that the webhook was sent by Tylt and that the payload has not been modified.

The HMAC signature is generated using:

```
HMAC-SHA256(raw POST data, API_SECRET)
```

The generated signature should be compared with the value received in the `X-TLP-SIGNATURE` header.

***

### Example Webhook Handling Code

```javascript
const express = require("express");
const crypto = require("crypto");

const app = express();
const PORT = 3000;
const apiSecretKey = "YOUR_TLP_API_SECRET_KEY";

// Middleware to parse incoming JSON requests
app.use(express.json());

// Callback endpoint
app.post("/callback", (req, res) => {
  const data = req.body;

  const tlpSignature = req.headers["x-tlp-signature"];

  const calculatedHmac = crypto
    .createHmac("sha256", apiSecretKey)
    .update(JSON.stringify(data))
    .digest("hex");

  if (calculatedHmac === tlpSignature) {
    console.log("Received Tylt webhook:", data);

    const eventId = data?.data?.eventDetails?.eventId;
    const instanceId = data?.data?.instanceId;
    const merchantOrderId = data?.data?.merchantOrderId;

    console.log("Event ID:", eventId);
    console.log("Instance ID:", instanceId);
    console.log("Merchant Order ID:", merchantOrderId);

    // Process the webhook based on eventId
    // 1  = Instance Created
    // 2  = Order Created
    // 3  = Payment Processing
    // 4  = Payment Completed
    // 8  = Payment Failed
    // 9  = Order Cancelled or Expired
    // 10 = KYC Failed

    return res.status(200).send("ok");
  }

  return res.status(400).send("Invalid HMAC signature");
});

app.listen(PORT, () => {
  console.log(`Server listening on port ${PORT}`);
});
```

### Webhook Acknowledgement

After receiving and validating the webhook, the partner must return:

```
HTTP 200
```

with the response body:

```
ok
```

If Tylt does not receive this acknowledgement, the webhook will not be retried automatically. Missed callbacks can be resent manually from the Tylt dashboard. ([Tylt Documentation](https://docs.tylt.money/introduction/tylt-crossramp-fiat-less-than-greater-than-crypto-solutions/philippines-php-english/instapay-pesonet-pay-out-widget/webhook-for-tylt-crossramp-pay-out))

***

### Important Considerations

| Area                 | Requirement                                                                                                           |
| -------------------- | --------------------------------------------------------------------------------------------------------------------- |
| Signature validation | Always verify the `X-TLP-SIGNATURE` header before processing the webhook.                                             |
| Response             | Always return HTTP `200` with `ok` in the response body after successful receipt.                                     |
| Manual retry         | If a callback is missed, the webhook can be manually resent from the Tylt dashboard.                                  |
| Lifecycle handling   | Use `eventDetails.eventId` to determine the current transaction state.                                                |
| Reconciliation       | Store `instanceId`, `merchantOrderId`, `eventId`, fiat amount, crypto amount, rate, and timestamp for reconciliation. |

***


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.tylt.money/introduction/tylt-crossramp-fiat-crypto-solutions/philippines-php/administration/webhook-for-administrators.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
