Webhooks allow your application to receive real-time notifications about events happening in our product.
This can be related to an order session or an operation of one of your staff members in the OrderLemon app.| Field | Type | Required | Description |
|---|---|---|---|
| Webhook name | string | Yes | The name of the webhook |
| Webhook url | string | Yes | The target url for the webhook, needs to be https |
| Custom headers | array | No | Optional custom headers to be included in each webhook, only valid pairs will be saved |
| Webhook secret | string | Yes | Used to verify that incoming requests are genuinely from OrderLemon |
| Async | boolean | No | |
| Events | array | Yes | The events that need to be sent to your webhook, at least 1 needs to be selected |
| Enabled | boolean | No |
It's crucial to verify our webhook requests. You can do this by using a secret. The Authorization header will show: Authorization: Bearer <secret>.
Always respond to webhook requests with a 200 OK status code quickly to acknowledge receipt, even if you process the event asynchronously.
You can add in the configuration screen as many extra headers as you want, we don't validate any of these apart from header formatting.
The following headers will be present in the webhook.
| Name | Type | Required | Description |
|---|---|---|---|
| Authorization | string | Yes | Secret key used to verify the webhook. |
| Content-Type | string | Yes | application/json |
<?php
header("Content-Type: application/json; charset=UTF-8");
function getAuthorizationHeader(): ?array {
$headers = null;
if (isset($_SERVER['Authorization'])) {
$headers = trim($_SERVER["Authorization"]);
} elseif (isset($_SERVER['HTTP_AUTHORIZATION'])) {
$headers = trim($_SERVER["HTTP_AUTHORIZATION"]);
} elseif (function_exists('apache_request_headers')) {
$requestHeaders = apache_request_headers();
$requestHeaders = array_combine(array_map('ucwords', array_keys($requestHeaders)), array_values($requestHeaders));
if (isset($requestHeaders['Authorization'])) $headers = trim($requestHeaders['Authorization']);
}
return $headers;
}
function getBearerToken(): ?string {
$headers = getAuthorizationHeader();
return empty($headers) ? null : trim(str_replace('Bearer', '', $headers));
}
define('ORDERLEMON_WEBHOOK_SECRET', 'secret');
$bearer = getBearerToken();
if (!isset($bearer) || !hash_equals(ORDERLEMON_WEBHOOK_SECRET, $bearer)) {
die('{"success": false}');
}
$dataInputRaw = file_get_contents("php://input");
// $dataInput = json_decode($dataInputRaw, true);
// ... code logic
die($dataInputRaw);
const express = require('express');
const crypto = require('crypto');
const app = express();
app.use(express.json());
function verifySignature(req) {
const authHeader = req.headers['authorization'];
const webhookSecret = 'YOUR_WEBHOOK_SECRET';
if (!authHeader || !authHeader.startsWith('Bearer ')) return false;
const token = authHeader.split(' ')[1];
const tokenBuffer = Buffer.from(token);
const secretBuffer = Buffer.from(webhookSecret);
if (tokenBuffer.length !== secretBuffer.length) return false;
return crypto.timingSafeEqual(tokenBuffer, secretBuffer);
}
app.post('/webhook', (req, res) => {
if (!verifySignature(req)) {
console.warn('Unauthorized webhook attempt');
return res.status(401).json({ error: 'Invalid signature' });
}
const payload = req.body;
console.log('Received webhook event:', payload.event);
if (payload.event === 'payments.completed') {
console.log('New payment received:', payload.orderlemon);
}
res.status(200).json({ received: true });
});
app.listen(3000, () => {
console.log('Webhook server listening on port 3000');
});