Skip to main content

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:

  • New
  • Processing
  • Settled
  • Expired
  • Invalid

Webhook statuses and suggested actions: