Skip to main content

Overview

Webhooks deliver instant notifications to your server when events occur — most critically, when a payment is completed. This is how your POS knows to show “Payment Received” to the cashier.

Setup

Via Partner Dashboard

  1. Go to Webhooks in the Partner Dashboard
  2. Click Create Webhook
  3. Enter your endpoint URL and select events
  4. Save — you’ll receive a webhook secret for signature verification

Via API

curl -X POST https://api.acountpay.com/v1/partner/webhooks \
  -H "X-Partner-Client-Id: your-client-id" \
  -H "X-Partner-Client-Secret: your-client-secret" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-pos.com/webhooks/acountpay",
    "events": ["payment.completed", "payment.failed"]
  }'

Events

Payment Events

EventDescriptionWhen
payment.completedPayment successfulCustomer completed bank authorization and payment settled
payment.failedPayment failedBank rejected, customer abandoned, or payment expired

Merchant Events

EventDescriptionWhen
merchant.activatedMerchant is now activeSent when merchant status transitions to active (e.g. after approval). Use this to create stores via the API.
merchant.deactivatedMerchant deactivatedSent when merchant status transitions to inactive.
Note: merchant.activated is dispatched as soon as the merchant becomes active. Subscribe to it so your system can automatically create stores for the merchant (e.g. POST /v1/partner/merchants/:merchantId/stores) and start accepting payments.

Payload Format

All webhooks use the same envelope: event, timestamp, and data. The data object varies by event.

payment.completed / payment.failed

{
  "event": "payment.completed",
  "timestamp": "2026-03-18T12:01:30.000Z",
  "data": {
    "paymentId": 456,
    "referenceNumber": "ORDER-123",
    "status": "paid",
    "amount": 149.50,
    "currency": "DKK",
    "merchantClientId": "a1b2c3d4-...",
    "merchantName": "Restaurant XYZ",
    "bankPaymentStatus": "AcceptedSettlementCompleted",
    "timestamp": "2026-03-18T12:01:30.000Z"
  }
}

merchant.activated / merchant.deactivated

{
  "event": "merchant.activated",
  "timestamp": "2026-03-19T10:00:00.000Z",
  "data": {
    "merchantId": 42,
    "clientId": "a1b2c3d4-e5f6-7890-abcd-1234567890ab",
    "companyName": "Restaurant XYZ ApS",
    "status": "active",
    "previousStatus": "pending",
    "timestamp": "2026-03-19T10:00:00.000Z"
  }
}
Use merchantId and clientId from the payload to create stores (POST /partner/merchants/:merchantId/stores) or to start sending payments for this merchant.

Signature Verification

Every webhook includes an X-Webhook-Signature header containing an HMAC-SHA256 signature of the request body, using your webhook secret. Always verify signatures to ensure webhooks are from AcountPay.
const crypto = require('crypto');

function verifyWebhook(body, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(JSON.stringify(body))
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

// Express handler
app.post('/webhooks/acountpay', (req, res) => {
  const signature = req.headers['x-webhook-signature'];
  if (!verifyWebhook(req.body, signature, WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }

  const { event, data } = req.body;

  if (event === 'payment.completed') {
    markOrderPaid(data.referenceNumber);
  }

  res.status(200).send('OK');
});

Testing Webhooks

Send a test webhook from the Partner Dashboard or via API:
curl -X POST https://api.acountpay.com/v1/partner/webhooks/{id}/test \
  -H "X-Partner-Client-Id: your-client-id" \
  -H "X-Partner-Client-Secret: your-client-secret"

Best Practices

  • Respond quickly: Return 200 within 10 seconds. Process asynchronously.
  • Idempotency: Use paymentId or X-Webhook-Id header to deduplicate.
  • Retry: Failed deliveries are not retried automatically. Use polling as a fallback.
  • HTTPS: Always use HTTPS for webhook endpoints.

Payment Scope

AcountPay handles payment initiation only. Once a payment is completed, any post-payment transactions such as refunds, returns, or partial refunds are the responsibility of the merchant or partner to manage directly with their bank or payment processor. There are no webhook events for refunds or chargebacks.