Webhooks

This guide explains how to implement webhook handling for payment status notifications in your application. Webhooks provide real-time updates about payment statuses directly to your backend system.

Implementation Requirements

When creating a payment, you can provide a webhookUrl endpoint where we will send payment status notifications. If provided, your system must:

  • Respond to webhook requests within 10 seconds
  • Return a 2xx HTTP status code to acknowledge successful receipt
  • Handle webhook payload validation

If your system fails to acknowledge a webhook, we will:

  • Retry the webhook delivery up to 5 times
  • Spread retries across a 72-hour period
  • Send an email notification after the final unsuccessful attempt

Webhook Payload

Each webhook request contains a JWT token in the request body:

{
  "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJwYXltZW50T3JkZXJJZCI6IjAxOTc1ODZjLWUzZjItNzNkNS04ZTI4LWMzMGM4YjY4YjQ3OSIsIm9yZGVyUmVmZXJlbmNlIjoiVEVTVC1kZjdhMzFmYy03MmQ0LTRmMmItYmJlZC1hNzlkZThkYTJkYjMiLCJwYXltZW50UHVycG9zZSI6IlRlc3Qgb3JkZXIgIzEyMzQiLCJwYXltZW50U3RhdHVzIjoiY29tcGxldGVkIiwicGF5bWVudERldGFpbHMiOnsiYW1vdW50IjoxMi4zNCwiY3VycmVuY3kiOiJFVVIiLCJkZWJ0b3JJYmFuIjoiTFQzNzczMDAwMTAwMTAyNjkzNjIifSwiZXZlbnQiOiJwYXltZW50LmNvbXBsZXRlZCJ9.Pbi6JJVqtY-J3jlcdAyd8DMkLQEjTRvdDSb85exjeeY"
}

The JWT token must be validated using your secret key to ensure the webhook's authenticity.

JWT Token Validation

import jwt from 'jsonwebtoken';

const token = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJwYXltZW50T3JkZXJJZCI6IjAxOTc1ODZjLWUzZjItNzNkNS04ZTI4LWMzMGM4YjY4YjQ3OSIsIm9yZGVyUmVmZXJlbmNlIjoiVEVTVC1kZjdhMzFmYy03MmQ0LTRmMmItYmJlZC1hNzlkZThkYTJkYjMiLCJwYXltZW50UHVycG9zZSI6IlRlc3Qgb3JkZXIgIzEyMzQiLCJwYXltZW50U3RhdHVzIjoiY29tcGxldGVkIiwicGF5bWVudERldGFpbHMiOnsiYW1vdW50IjoxMi4zNCwiY3VycmVuY3kiOiJFVVIiLCJkZWJ0b3JJYmFuIjoiTFQzNzczMDAwMTAwMTAyNjkzNjIifSwiZXZlbnQiOiJwYXltZW50LmNvbXBsZXRlZCJ9.Pbi6JJVqtY-J3jlcdAyd8DMkLQEjTRvdDSb85exjeeY';

const decoded = jwt.verify(token, 'your-secret-key');

Statuses

Webhooks will announce these status changes:

  • Name
    processing
    Description

    Payment order is being processing - we are waiting for banks confirmation. Eventualy it will become completed or canceled. In rare cases this can take up to two days.

  • Name
    completed
    Description

    Payment order has been successfully paid.

  • Name
    canceled
    Description

    Payment order was canceled by the client or the bank.

  • Name
    expired
    Description

    Payment session has expired without completion - user abandoned the payment.

  • Name
    failed
    Description

    Payment process failed due to technical issues on our end or with the banking system.

Decoded Webhook Payload Example

{
  "paymentOrderId": "0197586c-e3f2-73d5-8e28-c30c8b68b479",
  "orderReference": "TEST-df7a31fc-72d4-4f2b-bbed-a79de8da2db3",
  "paymentStatus": "completed",
  "paymentDetails": {
    "amount": 12.34,
    "currency": "EUR",
    "debtorIban": "LT377300010010269362"
  },
  "event": "payment.completed"
}

Payment lifecycle

Normally there should be only one Payment order status change - from pending to the one of listed above. But there are some edge cases where it may change between the ones listed above.

You should know that:

  • A payment order may transition from any other status (including canceled and failed) to completed.
  • Payment order will not transition from completedto other statuses.