Example file
send-event.php
PHP: signs and sends a sale from your CRM to an inbound custom integration's delivery URL.
<?php
// Sends one signed event to a Subcontext inbound custom integration, in PHP 8.1
// or later with the curl extension. Here it's a sale from your CRM, which
// Subcontext records as an outcome on the lead.
//
// Set these first (all three are on the integration's page in Subcontext):
// SUBCONTEXT_DELIVERY_URL the Delivery URL
// SUBCONTEXT_SIGNING_SECRET the value of the secret variable chosen as the Signing secret variable
// SUBCONTEXT_SIGNATURE_HEADER the Signature header (X-Integrations-Signature unless you changed it)
//
// Run it: php send-event.php
declare(strict_types=1);
$deliveryUrl = getenv('SUBCONTEXT_DELIVERY_URL') ?: '';
$secret = getenv('SUBCONTEXT_SIGNING_SECRET') ?: '';
$headerName = getenv('SUBCONTEXT_SIGNATURE_HEADER') ?: 'X-Integrations-Signature';
if ($deliveryUrl === '' || $secret === '') {
fwrite(STDERR, "Set SUBCONTEXT_DELIVERY_URL and SUBCONTEXT_SIGNING_SECRET.\n");
exit(1);
}
function signatureHeader(string $rawBody, string $secret, ?int $timestamp = null): string
{
$timestamp ??= time();
return 't=' . $timestamp . ',v1=' . hash_hmac('sha256', $timestamp . '.' . $rawBody, $secret);
}
// The shape is up to you. The integration's settings say where to find each part.
// This one fits an Event type path of "type" and the outcome mapping on the
// Integrations guide.
$event = [
'event_id' => bin2hex(random_bytes(16)), // send the same id again if you retry, so it's recorded once
'type' => 'deal.won',
'deal' => [
'id' => 'DEAL-123',
'contact_id' => 'YOUR_CRM_CONTACT_ID', // your id for the lead, or send ours (contact_id) instead
'closed_at' => gmdate('c'),
'commission' => '450.00',
],
];
// Sign the exact string you send.
$body = json_encode($event);
$curl = curl_init($deliveryUrl);
curl_setopt_array($curl, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $body,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 15,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
$headerName . ': ' . signatureHeader($body, $secret),
],
]);
curl_exec($curl);
$status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);
curl_close($curl);
// 200: accepted. 400: not JSON. 403: signature, secret or clock problem. 404: wrong URL.
echo $status, ' ', $status === 200 ? 'accepted' : 'not accepted', "\n";