Skip to main content

Callbacks

Process webhook notifications with built-in signature verification.

The Callbacks facade handles webhook signature verification and payload processing.

Overview​

When a payment status changes, Paysera sends a webhook to your callback URL. The SDK provides tools to:

  1. Verify the webhook signature
  2. Parse the payload into typed objects
  3. Extract payment information

Use processPaymentCallback() for combined verification and parsing:

<?php

use Paysera\CheckoutSdk\SdkFacadeBuilder;
use Paysera\CheckoutSdk\Exception\IntegrationException;
use Psr\Http\Message\ServerRequestInterface;

// Your webhook endpoint
function handleWebhook(ServerRequestInterface $request): void
{
$sdk = (new SdkFacadeBuilder())->build();
$callbacksFacade = $sdk->getCallbacksFacade();

try {
// Verify signature and parse payload
$callback = $callbacksFacade->processPaymentCallback($request);

// Extract event information
$eventName = $callback->getEvent()->getName();
$eventType = $callback->getEvent()->getType();

// Extract order information
$order = $callback->getOrder();
$orderId = $order->getId();
$status = $order->getOrderInfo()->getStatus();
$amount = $order->getOrderInfo()->getAmount();
$currency = $order->getOrderInfo()->getCurrency();

// Get your reference
$reference = $order->getMerchantData()['reference'];

// Process based on order status
$status = $order->getOrderInfo()->getStatus();

if ($order->getOrderInfo()->isPaid()) {
handlePaymentCompleted($reference, $order);
} else {
handleOrderUpdated($reference, $order, $status);
}

// Return success response
http_response_code(200);
echo $callbacksFacade->getCallbackResponseSuccessMessage();

} catch (IntegrationException $e) {
// Signature verification failed
error_log('Webhook verification failed: ' . $e->getMessage());
http_response_code(401);
}
}

Callback Object Structure​

$callback = $callbacksFacade->processPaymentCallback($request);

// Event information
$event = $callback->getEvent();
$eventName = $event->getName(); // e.g., 'order.amount_paid_updated'
$eventType = $event->getType(); // e.g., 'order'

// Order information
$order = $callback->getOrder();
$orderId = $order->getId();

// Order info (status, amount)
$orderInfo = $order->getOrderInfo();
$status = $orderInfo->getStatus(); // e.g., 'paid'
$amount = $orderInfo->getAmount(); // int (cents), e.g., 2500
$amountPaid = $orderInfo->getAmountPaid(); // int (cents)
$currency = $orderInfo->getCurrency(); // 'EUR'
$isPaid = $orderInfo->isPaid(); // bool - checks if status is 'paid'

// Merchant data (your reference) - MerchantData implements ArrayAccess
$merchantData = $order->getMerchantData();
$reference = $merchantData['reference']; // 'ORDER-12345'

// Payment links used
$paymentLinks = $order->getPaymentLinkCollection();
foreach ($paymentLinks as $link) {
$linkId = $link->getId();
$linkName = $link->getName();
$payerInfo = $link->getPayerInfo();
$payments = $link->getPayments(); // PaymentCollection
}

Manual Verification (Advanced)​

For more control, verify and parse separately:

Step 1: Verify Signature​

try {
$callbacksFacade->verifyCallbackRequest($request);
// Signature is valid
} catch (IntegrationException $e) {
// Signature verification failed
http_response_code(401);
exit;
}

Step 2: Parse Payload​

// After verification
$callback = $callbacksFacade->buildPaymentCallback($request);
// Process callback...

Step 3: Extract Headers (Optional)​

$headers = $callbacksFacade->getCallbackRequestHeaders($request);
// Access custom header information

Response Codes​

The SDK provides constants for response codes:

// Success code (200)
$successCode = $callbacksFacade->getCallbackResponseSuccessCode();

// Verification failed code (401)
$failedCode = $callbacksFacade->getCallbackResponseVerificationFailedCode();

// Success message
$successMessage = $callbacksFacade->getCallbackResponseSuccessMessage();

Complete Handler Example​

<?php

namespace App\Http\Controllers;

use Paysera\CheckoutSdk\SdkFacade;
use Paysera\CheckoutSdk\Exception\IntegrationException;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;

class PayseraWebhookController
{
private SdkFacade $sdk;
private OrderRepository $orders;

public function __construct(SdkFacade $sdk, OrderRepository $orders)
{
$this->sdk = $sdk;
$this->orders = $orders;
}

public function handle(ServerRequestInterface $request): ResponseInterface
{
$callbacksFacade = $this->sdk->getCallbacksFacade();

try {
$callback = $callbacksFacade->processPaymentCallback($request);

$eventName = $callback->getEvent()->getName();
$reference = $callback->getOrder()->getMerchantData()['reference'];
$status = $callback->getOrder()->getOrderInfo()->getStatus();

// Find local order
$order = $this->orders->findByReference($reference);
if (!$order) {
error_log("Order not found: $reference");
return $this->successResponse($callbacksFacade);
}

// Idempotency check
if ($order->paysera_status === $status) {
return $this->successResponse($callbacksFacade);
}

// Handle based on order status
if ($callback->getOrder()->getOrderInfo()->isPaid()) {
$this->handleCompleted($order, $callback);
} else {
$this->handleStatusUpdate($order, $callback);
}

return $this->successResponse($callbacksFacade);

} catch (IntegrationException $e) {
error_log('Webhook verification failed: ' . $e->getMessage());
return response('Verification failed', 401);
}
}

private function handleCompleted($order, $callback): void
{
$order->status = 'paid';
$order->paysera_status = 'completed';
$order->paid_at = now();

$order->save();

// Trigger fulfillment
event(new OrderPaid($order));
}

private function handleStatusUpdate($order, $callback): void
{
$status = $callback->getOrder()->getOrderInfo()->getStatus();
$order->paysera_status = $status;
$order->save();
}

private function successResponse($callbacksFacade): ResponseInterface
{
return response(
$callbacksFacade->getCallbackResponseSuccessMessage(),
$callbacksFacade->getCallbackResponseSuccessCode()
);
}
}