Skip to content

Webhooks

What is a Webhook?

Webhook (web hook) is a mechanism that allows Mesilat platform to automatically notify your server about important events in real time. When an event occurs (for example, successful payment), the platform sends an HTTP POST request to your specified URL with event data.

Webhook Data

When sending webhook, the following data is transmitted in request body:

  • additional_fields — additional fields that were configured in product settings and filled by buyer on checkout page
  • metadata — metadata that was passed when creating payment link (only for payment links)
  • Information about order, buyer and payment

Webhook Data Example

{
  "uuid": "b9c3e992",
  "amount": 500,
  "total_amount": 460,
  "currency": "RUB",
  "commission": 40,
  "exchange_rate": 1,
  "created_at": 1759919382,
  "metadata": [],
  "additional_fields": {
    "hidden_0": {
      "text": "platform_product_id=115123584",
      "type": "hidden",
      "value": null
    }
  },
  "customer_phone": "+35796612353",
  "customer_name": "Emma S.",
  "customer_email": "[email protected]",
  "product_id": 141,
  "product_title": "Custom Service",
  "product_type": "CustomService",
  "trigger_type": "auto"
}

Field Description

Transaction Information

Field Type Description
uuid string Unique transaction identifier. Use for ensuring idempotency
amount number Full payment amount in main currency units (e.g., 20 EUR)
total_amount number Final amount after platform commission deduction
commission number Platform commission amount deducted from transaction
currency string Payment currency. Possible values: EUR, USD, RUB
exchange_rate number Currency exchange rate (if conversion is applied)
created_at integer Transaction creation time in Unix timestamp format

Customer Data

Field Type Description
customer_name string Customer name specified during order placement
customer_email string Customer email
customer_phone string Customer phone in international format

Product Information

Field Type Description
product_id integer Unique product identifier
product_title string Product title
product_type string Product type (see table below)

Additional Data

Field Type Description
additional_fields object/array Additional fields configured in product and filled by buyer on checkout. See detailed structure description below
metadata object/array Metadata passed when creating payment link. Available only for payment links. May contain any user data or be empty array []
trigger_type string Webhook trigger type: auto (automatic on successful payment) or manual (test event)

Creating additional_fields

Additional fields are configured in Mesilat platform interface in "Customer Information" section of specific product:

Additional fields configuration

In the interface you can:

  1. Create additional fields of various types
  2. Configure which fields are required for filling

All fields filled by customer during order placement will be passed in webhook in additional_fields section.

additional_fields Format

additional_fields field can have two formats:

1. Empty array (if additional fields are not configured):

"additional_fields": []

2. Object with fields (if additional fields are configured and filled):

"additional_fields": {
  "field_name": {
    "text": "field value or description",
    "type": "field type (text, email, phone, hidden, etc.)",
    "value": "field value or null"
  }
}

Example with filled fields:

"additional_fields": {
  "hidden_0": {
    "text": "platform_product_id=115123584",
    "type": "hidden",
    "value": null
  },
  "text_1": {
    "text": "Additional information",
    "type": "text",
    "value": "Additional information"
  },
  "checkbox_2": {
    "text": "I agree to terms",
    "type": "checkbox",
    "value": "true"
  },
  "select_3": {
    "text": "Premium",
    "type": "select",
    "value": "Premium"
  }
}

Each field in additional_fields contains: - text — text value or field description - type — field type (see table of possible types below) - value — filled field value or null

Possible additional_fields Types

Type Description
text Text field
checkbox Checkbox (tick box)
radio Radio button (single choice)
select Dropdown list
link Link/URL field
hidden Hidden field

Product Types (product_type)

Value Description
DigitalDownload Digital product for download (files, documents, media)
CustomService Individual service
RecurringMembership Subscription with recurring payments

Webhook Security

Webhook Key

Each webhook is signed with special webhook_key that is passed in request header webhook-key. This allows you to verify that request actually came from Mesilat platform.

Request header:

webhook-key: your_webhook_key_here

Signature verification example:

// PHP
$webhookKey = $_SERVER['HTTP_WEBHOOK_KEY'] ?? '';
$expectedKey = getenv('MESILAT_WEBHOOK_KEY');

if ($webhookKey !== $expectedKey) {
    http_response_code(401);
    exit('Invalid webhook key');
}
// Node.js
const webhookKey = req.headers['webhook-key'];
const expectedKey = process.env.MESILAT_WEBHOOK_KEY;

if (webhookKey !== expectedKey) {
  return res.status(401).send('Invalid webhook key');
}
# Python
webhook_key = request.headers.get('webhook-key')
expected_key = os.getenv('MESILAT_WEBHOOK_KEY')

if webhook_key != expected_key:
    return Response('Invalid webhook key', status=401)

Webhook Configuration

Webhook is configured in Mesilat platform personal cabinet:

Webhook Configuration

Configuration Steps:

  1. Enable webhook — activate webhook notification sending function
  2. Specify your webhook URL — enter full URL address of your server that will receive notifications (e.g.: https://webhook-test.com/a6f72e919ce3f0c26f4a12cfa45c9a7a)
  3. Generate and save webhook key — create unique key for request signing and save it in secure place
  4. Click "Save" — apply settings
  5. Send test event to your webhook — check integration functionality by sending test request

Retry Attempts

Mesilat platform automatically retries webhook sending in case of failure (if your server didn't return 200 response code).

Retry Mechanism:

Total of up to 10 attempts with increasing intervals:

Attempt Interval
1 Immediately
2 1 minute
3 5 minutes
4 10 minutes
5 20 minutes
6 30 minutes
7 1 hour
8 1 hour
9 1 hour
10 1 hour

Successful Delivery Conditions:

✅ Your server should return HTTP response code 200 to confirm webhook receipt

❌ Any other codes (4xx, 5xx) or timeout will be considered failed attempt

Failure Notification

If after 10 attempts webhook still wasn't delivered, notification email will be sent with information about the problem. This allows you to quickly respond to integration failure.

Webhook Processing Requirements

Fast Response

Your endpoint should respond quickly (within 5-10 seconds). If data processing requires time, use asynchronous processing:

  1. Receive webhook
  2. Save data to queue/database
  3. Immediately return code 200
  4. Process data in background

Idempotency

Webhook may be delivered multiple times (on retry attempts). Ensure that repeated processing of same event doesn't lead to action duplication. Use transaction uuid for uniqueness check.

Handler Example

// PHP (Laravel)
Route::post('/webhooks/mesilat', function (Request $request) {
    // Webhook key verification
    $webhookKey = $request->header('webhook-key');
    if ($webhookKey !== config('mesilat.webhook_key')) {
        return response('Unauthorized', 401);
    }

    // Data retrieval
    $data = $request->all();
    $uuid = $data['uuid'];

    // Idempotency check
    if (Order::where('transaction_uuid', $uuid)->exists()) {
        return response('OK', 200); // Already processed
    }

    // Add to queue for processing
    ProcessWebhookJob::dispatch($data);

    // Quick response
    return response('OK', 200);
});
// Node.js (Express)
app.post('/webhooks/mesilat', async (req, res) => {
  // Webhook key verification
  const webhookKey = req.headers['webhook-key'];
  if (webhookKey !== process.env.MESILAT_WEBHOOK_KEY) {
    return res.status(401).send('Unauthorized');
  }

  const data = req.body;
  const uuid = data.uuid;

  // Idempotency check
  const exists = await Order.findOne({ transactionUuid: uuid });
  if (exists) {
    return res.status(200).send('OK'); // Already processed
  }

  // Add to queue
  await queue.add('processWebhook', data);

  // Quick response
  res.status(200).send('OK');
});
# Python (Flask)
@app.route('/webhooks/mesilat', methods=['POST'])
def webhook():
    # Webhook key verification
    webhook_key = request.headers.get('webhook-key')
    if webhook_key != os.getenv('MESILAT_WEBHOOK_KEY'):
        return Response('Unauthorized', status=401)

    data = request.json
    uuid = data['uuid']

    # Idempotency check
    if Order.query.filter_by(transaction_uuid=uuid).first():
        return Response('OK', status=200)  # Already processed

    # Add to queue
    process_webhook.delay(data)

    # Quick response
    return Response('OK', status=200)

Debugging

Logging

It's recommended to log all incoming webhooks for debugging:

// PHP
Log::info('Webhook received', [
    'uuid' => $data['uuid'],
    'product_id' => $data['product_id'],
    'amount' => $data['amount'],
    'trigger_type' => $data['trigger_type'],
    'data' => $data
]);

Testing

Use "Send test event" function in webhook settings to check integration before going to production.

Delivery Verification

In platform personal cabinet you can see webhook sending history and status of each delivery attempt.