With API
Use this guide if you want to build directly against the ePay API.
The API gives you full backend control over your payment flow. You can create payments, handle results, update your own order system and build the checkout experience that fits your product.
What you will do
In this guide, you will:
Authenticate with your API key
Create an order in your own system
Create a payment session with ePay
Inspect the response
Test the payment
Handle the result server-side
Before you start
You need:
- An API key
- A Point of Sale ID
- A backend environment
- A tool for making API requests
- A notification URL or webhook
You can use cURL, Postman, Insomnia or your own backend code.
Your API key must only be used server-side. Never expose your API key in frontend code.
Step 1: Understand authentication
Authenticate API requests with your API key.
Authorization: Bearer <TEST_API_KEY>Use your test API key while building and testing.
Switch to your live API key only when your account is ready for live payments.
Step 2: Use idempotency
When creating payments, include an idempotency key.
This helps prevent duplicate payments if your system retries a request.
Idempotency-Key: <UUID>Use a unique value for each payment creation attempt.
Step 3: Create an order in your own system
Before creating the payment in ePay, create an order in your own system.
Set the order status to pending.
const order = await createOrder({ reference: "ORDER-1001", amount: 10000, currency: "DKK", status: "pending",});The order should not be marked as paid until your backend receives and verifies the payment result.
Step 4: Create the payment
Send a request to create a payment session.
API referencePOSTInitialize Payment Session/public/api/v1/citInitializes a new payment session with the ePay Payments API.
const body = JSON.stringify({ "pointOfSaleId": "<POINT_OF_SALE_ID>", "amount": 10000, "currency": "DKK", "reference": "ORDER-1001", "notificationUrl": "https://example.com/api/epay/notification", "successUrl": "https://example.com/payment/success", "failureUrl": "https://example.com/payment/failure"})fetch("https://payments.epay.eu/public/api/v1/cit", { method: "POST", headers: { "Content-Type": "application/json", "Authorization": "Bearer <TEST_API_KEY>", "Idempotency-Key": "<UUID>" }, body})Use your actual ePay endpoint and the required fields for your payment type.
Step 5: Understand the request
| Field | Description |
|---|---|
pointOfSaleId | Identifies which webshop, sales channel or system the payment belongs to |
amount | The amount in minor units |
currency | The payment currency |
reference | Your own order reference |
notificationUrl | Where ePay sends the payment result |
successUrl | Where the customer is redirected after success |
failureUrl | Where the customer is redirected after failure |
The reference should connect the ePay payment to your internal order.
Step 6: Inspect the response
The response contains the payment information your system needs.
Depending on your integration, this may include:
- Payment ID
- Session ID
- Session key
- Payment window URL
- Status
- Expiration time
For embedded flows such as Blocks, the most important response fields are session.id, key, and javascript.
Example:
{ "paymentWindowUrl": "https://payments.epay.eu/payment-window?sessionId=0192473a-e382-79a9-bfc2-65da88fe812f&sessionKey=4651656e-f29e-4dfa-a1cd-a65647862011", "session": { "id": "0192473a-e382-79a9-bfc2-65da88fe812f", "state": "PENDING" }, "key": "4651656e-f29e-4dfa-a1cd-a65647862011", "javascript": "https://payments.epay.eu/sessions/0192473a-e382-79a9-bfc2-65da88fe812f/client.js"}Store the identifiers you need to match future payment results to your order.
Do not store sensitive payment data.
Step 7: Send the customer to payment
What you do next depends on your frontend integration.
If you use Checkout, redirect the customer to the payment window URL.
return redirect(payment.paymentWindowUrl);If you use Blocks, return the session values needed by ePay.js.
return { sessionId: payment.session.id, sessionKey: payment.key, javascript: payment.javascript,};The sessionKey and javascript URL are scoped to this exact payment session.
Only return values that are safe to expose to the frontend.
Never return your API key.
Step 8: Complete a test payment
Complete the payment using a test card.
Test at least:
- A successful payment
- A failed payment
- A cancelled or abandoned payment
- A duplicate notification
- A retry from your own backend
Step 9: Handle the payment result
Use your notification URL or webhook to update your order.
Recommended backend flow:
Receive payment result from ePay
Verify that the result is valid
Find the order using the payment ID or reference
Check whether the order has already been processed
Update the order status
Return a successful response
Your notification handler should be safe to run more than once.
Example notification handler
export async function handlePaymentNotification(payload) { const payment = await verifyPaymentResult(payload); const order = await findOrderByReference(payment.reference); if (!order) { throw new Error("Order not found"); } if (order.status === "paid") { return { ok: true }; } if (payment.status === "accepted") { await markOrderAsPaid(order.id); } if (payment.status === "declined") { await markOrderAsFailed(order.id); } return { ok: true };}This is only an example. Your implementation should match your own order system and the actual ePay payment result format.
Common API errors
400 Bad Request
The request is invalid.
Check that:
- Required fields are included
- Field names are correct
- Amount is in the correct format
- Currency is supported
- URLs are valid
401 Unauthorized
The API key is missing or invalid.
Check that:
- The authorization header is included
- The API key is correct
- The API key belongs to the correct environment
422 Validation Error
The request is understood, but one or more values are not valid.
Check that:
- The Point of Sale ID exists
- The payment method is available
- The amount is allowed
- The currency is available for the Point of Sale
429 Rate Limited
Too many requests were sent in a short period.
Add retry handling with backoff.
Do not retry payment creation without idempotency.
What you built
You have now created your first payment with the ePay API.
You authenticated with your API key, created a payment session, inspected the response and prepared your backend to handle the payment result.