WordPress / WooCommerce
For plugin-based WordPress integration (WooCommerce, GiveWP, etc.), see Use Cases → WordPress Integration.
This page contains code examples for developers building custom WordPress integrations or extending existing plugins.
Create an invoice from a WordPress plugin
<?php
function coinsnap_create_invoice_for_order(WC_Order $order): array {
$api_key = get_option('coinsnap_api_key');
$store_id = get_option('coinsnap_store_id');
$body = [
'amount' => $order->get_total(),
'currency' => get_woocommerce_currency(),
'orderId' => (string) $order->get_id(),
'buyerEmail' => $order->get_billing_email(),
'redirectUrl' => $order->get_checkout_order_received_url(),
];
$response = wp_remote_post(
"https://app.coinsnap.io/api/v1/stores/{$store_id}/invoices",
[
'headers' => [
'x-api-key' => $api_key,
'Content-Type' => 'application/json',
],
'body' => json_encode($body),
'timeout' => 15,
]
);
if (is_wp_error($response)) {
throw new RuntimeException($response->get_error_message());
}
$code = wp_remote_retrieve_response_code($response);
$data = json_decode(wp_remote_retrieve_body($response), true);
if ($code >= 400) {
throw new RuntimeException("Coinsnap API error {$code}: " . ($data['message'] ?? ''));
}
return $data;
}
Handle webhooks in a custom plugin
<?php
// Register the REST endpoint
add_action('rest_api_init', function () {
register_rest_route('coinsnap/v1', '/webhook', [
'methods' => 'POST',
'callback' => 'coinsnap_handle_webhook',
'permission_callback' => '__return_true',
]);
});
function coinsnap_handle_webhook(WP_REST_Request $request): WP_REST_Response {
$payload = $request->get_body();
$signature = $request->get_header('x-coinsnap-sig');
$secret = get_option('coinsnap_webhook_secret');
$expected = 'sha256=' . hash_hmac('sha256', $payload, $secret);
if (!hash_equals($expected, $signature ?? '')) {
return new WP_REST_Response('Unauthorized', 401);
}
$event = json_decode($payload, true);
$order_id = $event['metadata']['orderId'] ?? null;
$order = $order_id ? wc_get_order((int) $order_id) : null;
if (!$order) {
return new WP_REST_Response('Order not found', 404);
}
switch ($event['type']) {
case 'New':
// Payment attempt started — no action needed
break;
case 'Processing':
// Full amount received on-chain, waiting for block confirmation
$order->update_status('on-hold', 'Coinsnap payment detected; waiting for confirmation.');
break;
case 'Settled':
// Idempotency guard
if ($order->is_paid()) {
break;
}
$order->payment_complete($event['invoiceId'] ?? '');
if (($event['additionalStatus'] ?? '') === 'Overpaid') {
$order->add_order_note('Coinsnap invoice was overpaid. Review the payment manually.');
}
if (($event['additionalStatus'] ?? '') === 'PaidAfterExpiration') {
$order->add_order_note('Coinsnap payment arrived after invoice expiration. Manual review required.');
break;
}
break;
case 'Expired':
if (($event['additionalStatus'] ?? '') === 'Underpaid') {
$order->update_status('on-hold', 'Coinsnap invoice expired with a partial payment.');
} else {
$order->update_status('cancelled', 'Coinsnap invoice expired.');
}
break;
case 'Invalid':
$order->update_status('cancelled', 'Coinsnap invoice was marked invalid.');
break;
}
return new WP_REST_Response('OK', 200);
}
Webhook URL: https://yoursite.com/wp-json/coinsnap/v1/webhook
Handled statuses in this example:
NewProcessingSettledExpiredInvalid
Webhook statuses and suggested actions: