Looking for ePay classic docs? Go to docs.epay.dk
ePay documentationDocsePay documentation

Pre-authorization webhooks

Use pre-authorization webhooks when your backend must review or adjust a transaction after the shopper has entered payment data, but before authorization or SCA begins.

This is an advanced flow. Most merchants should start without preAuthUrl and only enable it when they have a concrete need such as risk rules, custom anti-fraud checks, or server-side validation of dynamic amounts.

What pre-authorization webhooks do

When preAuthUrl is set on a payment session, ePay sends a server-to-server callback after payment data collection is complete and before authorization starts.

This gives your backend one last decision point where it can:

  • Reject the transaction
  • Force a different scaMode
  • Update exemptions
  • Add or merge transaction attributes
  • Change instantCapture

Typical use cases:

  • Run custom anti-fraud or risk checks
  • Verify a shopper-selected amount when dynamicAmount is enabled
  • Add server-side attributes before authorization
  • Escalate some transactions to stronger SCA handling

Before you use it

You need:

  • A payment session flow that uses POST /public/api/v1/cit or another supported session flow
  • A backend endpoint that can receive ePay callbacks
  • Webhook-style authorization validation on that endpoint
  • A response path that can decide quickly whether to reject or update the transaction

Pre-authorization webhooks must be enabled by ePay before use. Contact ePay if necessary.

How it fits into the payment flow

The flow usually looks like this:

Create a payment session and include preAuthUrl

The shopper selects a payment method and enters payment details

ePay sends the pre-authorization webhook to your backend

Your backend accepts, rejects, or updates the transaction settings

ePay continues with authorization and SCA based on the response

Enable it on the payment session

Include preAuthUrl when creating the payment session.

{  "pointOfSaleId": "<POINT_OF_SALE_ID>",  "amount": 10000,  "currency": "DKK",  "reference": "ORDER-1001",  "notificationUrl": "https://example.com/api/epay/notification",  "preAuthUrl": "https://example.com/api/epay/pre-auth",  "successUrl": "https://example.com/payment/success",  "failureUrl": "https://example.com/payment/failure"}

This can be used with Checkout, Blocks, payment links, subscription initialization, and other payment-session-based flows where preAuthUrl is supported.

What ePay sends

The pre-authorization webhook request contains the current session and transaction context. For card payments, it also includes card metadata that can be used in risk analysis.

Example request payload:

{  "session": {    "id": "0192473a-e382-79a9-bfc2-65da88fe812f",    "subscriptionId": "01929a94-5fce-7ccc-a7e4-7e9249133b39",    "amount": 1000,    "attributes": { "key1": "value1", "key2": "value2" },    "exemptions": ["TRA"],    "createdAt": "2024-10-01T10:38:14.658688472+02:00",    "currency": "DKK",    "expiresAt": "2024-10-01T12:41:14.658688472+02:00",    "instantCapture": "OFF",    "maxAttempts": 10,    "attempts": 1,    "reportFailure": false,    "dynamicAmount": false,    "notificationUrl": "https://example.com/notification",    "preAuthUrl": "https://example.com/pre-auth",    "successUrl": "https://example.com/success",    "failureUrl": "https://example.com/failure",    "pointOfSaleId": "0192473a-e381-705c-b61c-fc2ac9624afc",    "reference": "reference-1",    "state": "PROCESSING",    "textOnStatement": "The text",    "scaMode": "SKIP",    "timeout": 60  },  "transaction": {    "id": "01924756-d1f6-7bc6-bb51-2b5f87b43925",    "subscriptionId": "01929a94-5fce-7ccc-a7e4-7e9249133b39",    "state": "PROCESSING",    "errorCode": null,    "createdAt": "2024-10-01T09:08:45.174774Z",    "sessionId": "01924756-badd-71d4-be55-da367f434da4",    "paymentMethodId": "01924756-d1f6-738d-8040-90d76cedf01f",    "paymentMethodType": "CARD",    "paymentMethodSubType": "Visa",    "paymentMethodExpiry": "2050-01-01",    "paymentMethodDisplayText": "40000000XXXX0003",    "customerId": "User159",    "scaMode": "SKIP",    "amount": 1000,    "currency": "DKK",    "instantCapture": "OFF",    "notificationUrl": "https://example.com/notification",    "pointOfSaleId": "0192473a-e381-705c-b61c-fc2ac9624afc",    "reference": "reference-1",    "textOnStatement": "The text",    "exemptions": ["TRA"],    "attributes": { "key1": "value1", "key2": "value2" },    "clientIp": "1.2.3.4",    "type": "PAYMENT"  },  "card": {    "pan": "40000000XXXX0003",    "expireMonth": "01",    "expireYear": "30",    "issuer": "Danske Bank",    "scheme": "Visa",    "country": "DK",    "funding": "debit",    "segment": "consumer"  }}

How your backend responds

Your endpoint can reject the transaction or return updates that ePay should apply before continuing.

Example response:

{  "reject": false,  "update": {    "scaMode": "FORCE",    "exemptions": ["TRA"],    "attributes": { "key": "value" },    "instantCapture": "VOID"  }}

Response fields:

FieldDescriptionRequired
rejectIf true, the transaction is rejected and no authorization is attemptedNo
update.scaModeUpdates the SCA mode. Must be a valid scaMode valueNo
update.exemptionsReplaces the exemptions used when applicableNo
update.attributesRecursively merges attributes into the existing transaction attributesNo
update.instantCaptureUpdates the instantCapture modeNo

Security and operational notes

Use the same defensive webhook handling here as in your normal payment result flow.

  • Validate the incoming Authorization header before trusting the payload
  • Log enough context to understand why a transaction was rejected or updated
  • Keep the decision logic fast and deterministic
  • Treat this as a server-side control point, not a place for long-running business logic
DocumentationReuse the same webhook handling basicsUse the payment-result guide for authorization validation, retries, duplicate handling, and general webhook design.

Dynamic amount and pre-auth

If you enable dynamicAmount, the shopper can influence the amount client-side.

That makes pre-authorization webhooks especially important, because your backend can validate whether the chosen amount is allowed before authorization begins.

Most merchants are advised against using dynamic amounts because it increases integration complexity.

If you do enable it, validate the selected amount server-side in your pre-authorization webhook.

Liability notes

Pre-authorization responses can change who carries risk in some flows.

  • Setting scaMode to FORCE shifts liability to the issuer
  • Using exemptions can shift liability to the merchant

When to avoid pre-auth

Do not add pre-authorization webhooks just because they exist.

Avoid them if you only need a normal payment flow with server-side notification handling after the payment attempt is complete.

In that case, keep the session simple and rely on your normal notification URL or webhook instead.

How is this guide?

On this page