Server
PHP SDK
Drop-in PHP implementation for integrating YardPay Pro into server-side applications. Uses cURL — no Composer packages required.
API Client
Create YardPayProClient.php
<?php
// YardPayProClient.php
class YppException extends Exception
{
public int $status;
public string $code;
public function __construct(int $status, string $code, string $message)
{
parent::__construct($message);
$this->status = $status;
$this->code = $code;
}
}
class YardPayProClient
{
private string $apiKey;
private string $baseUrl;
private int $timeout;
public function __construct(string $apiKey, string $baseUrl = '', int $timeout = 30)
{
$this->apiKey = $apiKey;
$this->baseUrl = rtrim($baseUrl, '/');
$this->timeout = $timeout;
}
public function request(string $method, string $path, ?array $body = null, ?array $params = null): mixed
{
$url = $this->baseUrl . $path;
if ($params) {
$url .= '?' . http_build_query($params);
}
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => $this->timeout,
CURLOPT_CUSTOMREQUEST => $method, // GET, POST, PUT, DELETE
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'x-api-key: ' . $this->apiKey,
],
]);
if ($body !== null) {
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body));
}
$response = curl_exec($ch);
$statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$curlError = curl_error($ch);
curl_close($ch);
if ($curlError) {
throw new YppException(0, 'network_error', $curlError);
}
if ($statusCode === 204) {
return null;
}
if ($statusCode >= 400) {
$err = json_decode($response, true) ?? [];
throw new YppException(
$statusCode,
$err['code'] ?? 'api_error',
$err['message'] ?? "HTTP $statusCode"
);
}
$data = json_decode($response, true);
// Handle OData { "value": [...] } wrapper
if (is_array($data) && array_key_exists('value', $data)) {
return $data['value'];
}
return $data;
}
public function get(string $path, ?array $params = null): mixed
{
return $this->request('GET', $path, null, $params);
}
public function post(string $path, array $body): mixed
{
return $this->request('POST', $path, $body);
}
public function put(string $path, array $body): mixed
{
return $this->request('PUT', $path, $body);
}
public function delete(string $path): mixed
{
return $this->request('DELETE', $path);
}
}Services
Create YardPayProServices.php
<?php
// YardPayProServices.php
require_once __DIR__ . '/YardPayProClient.php';
class PaymentsService
{
private YardPayProClient $client;
public function __construct(YardPayProClient $client)
{
$this->client = $client;
}
/** Pay an invoice with card or saved funding source */
public function payInvoice(array $data): array
{
return $this->client->post('/api/payment/payinvoice', $data);
}
/** Get available payment methods for an invoice */
public function getPaymentMethods(int $invoiceId): array
{
return $this->client->get("/v1/invoice/$invoiceId/PaymentMethods");
}
/** List saved funding sources */
public function getFundingSources(): array
{
return $this->client->get('/v1/FundingSource');
}
/** Register a new card */
public function registerCard(array $card, string $name): array
{
return $this->client->post('/v1/payment/RegisterCard', [
'card' => $card,
'name' => $name,
]);
}
/** Verify a registered card */
public function verifyCard(int $fundingSourceId, string $code): void
{
$this->client->post("/v1/fundingSource/$fundingSourceId/verify", [
'VerificationCode' => $code,
]);
}
}
class InvoicesService
{
private YardPayProClient $client;
public function __construct(YardPayProClient $client)
{
$this->client = $client;
}
/** Get invoice by public reference code (no auth needed) */
public function getByReference(string $code): array
{
return $this->client->get("/v1/invoice/getByReference(code='$code')");
}
/** Get invoice by ID */
public function getById(int $id, ?string $expand = null): array
{
$params = $expand ? ['$expand' => $expand] : null;
return $this->client->get("/v1/invoice/$id", $params);
}
/** List invoices with OData filtering */
public function list(?string $filter = null, ?string $orderBy = null, int $top = 20, int $skip = 0): array
{
$params = ['$top' => $top, '$skip' => $skip];
if ($filter) $params['$filter'] = $filter;
if ($orderBy) $params['$orderby'] = $orderBy;
return $this->client->get('/v1/invoice', $params);
}
/** Create a new invoice */
public function create(array $data): array
{
return $this->client->post('/v1/invoice', $data);
}
/** Get QR code URL */
public function getQrCodeUrl(string $identifier, string $baseUrl = ''): string
{
return "$baseUrl/v1/invoice/qrcode/$identifier";
}
}
class SubscriptionsService
{
private YardPayProClient $client;
public function __construct(YardPayProClient $client)
{
$this->client = $client;
}
// Products
public function listProducts(?array $params = null): array { return $this->client->get('/v1/SubscriptionProduct', $params); }
public function createProduct(array $data): array { return $this->client->post('/v1/SubscriptionProduct', $data); }
public function updateProduct(int $id, array $data): array { return $this->client->put("/v1/SubscriptionProduct/$id", $data); }
public function deleteProduct(int $id): void { $this->client->delete("/v1/SubscriptionProduct/$id"); }
// Plans
public function listPlans(?array $params = null): array { return $this->client->get('/v1/SubscriptionPlan', $params); }
public function createPlan(array $data): array { return $this->client->post('/v1/SubscriptionPlan', $data); }
public function updatePlan(int $id, array $data): array { return $this->client->put("/v1/SubscriptionPlan/$id", $data); }
public function deletePlan(int $id): void { $this->client->delete("/v1/SubscriptionPlan/$id"); }
// Inventory
public function listInventory(?array $params = null): array { return $this->client->get('/v1/SubscriptionInventoryItem', $params); }
public function createInventoryItem(array $data): array { return $this->client->post('/v1/SubscriptionInventoryItem', $data); }
public function updateInventoryItem(int $id, array $data): array { return $this->client->put("/v1/SubscriptionInventoryItem/$id", $data); }
public function deleteInventoryItem(int $id): void { $this->client->delete("/v1/SubscriptionInventoryItem/$id"); }
}Usage
<?php
require_once __DIR__ . '/YardPayProServices.php';
$client = new YardPayProClient('sk_test_YOUR_KEY');
$payments = new PaymentsService($client);
$invoices = new InvoicesService($client);
// Create an invoice
$invoice = $invoices->create([
'description' => 'Order #1234',
'currencyCode' => 'JMD',
'items' => [
['name' => 'Widget', 'unitCost' => 100, 'quantity' => 2, 'invoiceItemTypeId' => 'Product'],
],
'sourceInfo' => [
'firstName' => 'Test',
'lastName' => 'User',
'email' => '[email protected]',
],
]);
echo "Invoice: " . $invoice['identifier'] . PHP_EOL;
// Get payment methods
$methods = $payments->getPaymentMethods($invoice['id']);
$cardMethod = array_values(array_filter($methods, fn($m) => $m['paymentMethodId'] === 'CreditCard'))[0];
// Pay the invoice
$result = $payments->payInvoice([
'invoiceIdentifier' => $invoice['identifier'],
'paymentOptionId' => $cardMethod['id'],
'card' => [
'name' => 'Test User',
'cardNumber' => '4111111111111111',
'expiryDate' => '12/28',
'cvv' => '123',
],
]);
if ($result['isSuccess']) {
echo "Paid: " . $result['referenceNumber'] . PHP_EOL;
}Webhook Signature Verification
<?php
// webhook.php
function verifyWebhookSignature(string $payload, string $signature, string $secret): bool
{
$expected = hash_hmac('sha256', $payload, $secret);
return hash_equals($expected, $signature);
}
// Handle incoming webhook
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_YPP_SIGNATURE'] ?? '';
$secret = getenv('YARDPAYPRO_WEBHOOK_SECRET');
if (!verifyWebhookSignature($payload, $signature, $secret)) {
http_response_code(401);
exit('Invalid signature');
}
$event = json_decode($payload, true);
switch ($event['type']) {
case 'payment.completed':
$paymentId = $event['data']['referenceNumber'];
// Handle completed payment
break;
case 'invoice.paid':
$invoiceId = $event['data']['id'];
// Handle paid invoice
break;
}
http_response_code(200);Error Handling
try {
$result = $payments->payInvoice([...]);
} catch (YppException $e) {
switch ($e->status) {
case 401:
echo "Invalid API key" . PHP_EOL;
break;
case 403:
echo "Insufficient scope: " . $e->code . PHP_EOL;
break;
case 400:
echo "Validation error: " . $e->getMessage() . PHP_EOL;
break;
default:
echo "API error {$e->status}: {$e->getMessage()}" . PHP_EOL;
}
}Requirements
- PHP 8.1+
ext-curlandext-json(standard in most PHP installations)- No Composer packages required — copy the files into your project
- Works with any PHP framework (Laravel, Symfony, WordPress, etc.)