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
dynamicAmountis 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/citor 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:
| Field | Description | Required |
|---|---|---|
reject | If true, the transaction is rejected and no authorization is attempted | No |
update.scaMode | Updates the SCA mode. Must be a valid scaMode value | No |
update.exemptions | Replaces the exemptions used when applicable | No |
update.attributes | Recursively merges attributes into the existing transaction attributes | No |
update.instantCapture | Updates the instantCapture mode | No |
Security and operational notes
Use the same defensive webhook handling here as in your normal payment result flow.
- Validate the incoming
Authorizationheader 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
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
scaModetoFORCEshifts 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.