PaidBy (Open Banking)
Overview
The merchant backend submits a PaidBy authorization request. A successful API response includes a redirect_url that the merchant frontend uses to open the hosted transaction page. Final payment status must be confirmed through notifications and transaction states.
Integration flow
The PaidBy Open Banking flow consists of 4 steps:
- Create an API request.
- Receive the API response.
- Open the ISX transaction page.
- Display the result page.
The merchant backend should create the API request because the request contains merchant credentials and configuration that must not be exposed in frontend code.
|
Merchant frontend |
Create an API request
POST /v1/authorization/
The API request consists of the HTTP method, URL, headers and JSON body. Different data may be included in the request, but the required objects and fields must be supplied for a successful transaction flow.
API endpoints
|
Environment |
Method |
API URL |
|
stage |
POST |
|
|
production |
POST |
Use the stage URL while developing and testing the integration. Use the production URL only after the merchant account and production configuration have been approved.
Request headers
The API header values are provided by the ISX relationship management team.
From: YOUR_API_CLIENT_NAME
Authorization: Bearer YOUR_API_TOKEN
Content-Type: application/json
|
Header |
Value |
Required |
Description |
|
|
|
Yes |
Identifies the API client. |
|
|
|
Yes |
Bearer token used to authenticate the request. |
|
|
|
Yes |
Indicates that the request body contains JSON. |
⚠️ The word Bearer must be included before the API token. Omitting it will cause an authentication error. Do not expose the From value or bearer token in frontend code.
Request objects
|
Object |
Description |
Required |
|
|
Workflow name supplied by the ISX relationship management team. |
Yes |
|
|
Information and configuration relating to the merchant. |
Yes |
|
|
Information about the payment transaction. |
Yes |
|
|
Information about the client making the payment. |
Yes |
|
|
Information identifying the client account. |
Yes |
|
|
Information about the bank account to debit. Used for applicable EUR payments. |
Conditional |
Replace the example workflow and merchant values with those supplied for the merchant integration.
EUR request example
cURL
curl "https://stage-gateway.isignth.is/v1/authorization/" \
--request POST \
--header "From: YOUR_API_CLIENT_NAME" \
--header "Authorization: Bearer YOUR_API_TOKEN" \
--header "Content-Type: application/json" \
--data '{
"workflow": "Test_Workflow",
"merchant": {
"id": "Test_Merchant",
"transaction_webhook_url": "https://...",
"return_url": "https://..."
},
"client": {
"first_name": "Shana",
"last_name": "Barrows",
"email": "shana.barrows@mail.com"
},
"transaction": {
"id": "Test_ID",
"amount": "100",
"currency": "EUR",
"reference": "Test_Ref"
},
"account_holder": {
"name": "Jane Smith",
"type": "business",
"iban": "DE89370400440532013000",
"bic": "COBADEFFXXX"
},
"account": {
"identifier": "Test_ID"
}
}'
JSON body
{
"workflow": "Test_Workflow",
"merchant": {
"id": "Test_Merchant",
"transaction_webhook_url": "https://...",
"return_url": "https://..."
},
"client": {
"first_name": "Shana",
"last_name": "Barrows",
"email": "shana.barrows@mail.com"
},
"transaction": {
"id": "Test_ID",
"amount": "100",
"currency": "EUR",
"reference": "Test_Ref"
},
"account_holder": {
"name": "Jane Smith",
"type": "business",
"iban": "DE89370400440532013000",
"bic": "COBADEFFXXX"
},
"account": {
"identifier": "Test_ID"
}
}
GBP request example
cURL
curl "https://stage-gateway.isignth.is/v1/authorization/" \
--request POST \
--header "From: YOUR_API_CLIENT_NAME" \
--header "Authorization: Bearer YOUR_API_TOKEN" \
--header "Content-Type: application/json" \
--data '{
"workflow": "Test_Workflow",
"merchant": {
"id": "Test_Merchant",
"transaction_webhook_url": "https://...",
"return_url": "https://..."
},
"client": {
"first_name": "Shana",
"last_name": "Barrows",
"email": "shana.barrows@mail.com"
},
"transaction": {
"id": "Test_ID",
"amount": "100",
"currency": "GBP",
"reference": "Test_Ref"
},
"account": {
"identifier": "Test_ID"
}
}'
JSON body
{
"workflow": "Test_Workflow",
"merchant": {
"id": "Test_Merchant",
"transaction_webhook_url": "https://...",
"return_url": "https://..."
},
"client": {
"first_name": "Shana",
"last_name": "Barrows",
"email": "shana.barrows@mail.com"
},
"transaction": {
"id": "Test_ID",
"amount": "100",
"currency": "GBP",
"reference": "Test_Ref"
},
"account": {
"identifier": "Test_ID"
}
}
Request-field reference
Workflow
|
Field |
Type |
Required |
Description |
|
|
String |
Yes |
Workflow name supplied by the ISX relationship management team. |
Merchant object
|
Field |
Type |
Required |
Description |
|
|
String |
Yes |
Merchant identifier supplied by the ISX relationship management team. |
|
|
String |
Yes |
Merchant endpoint that receives transaction notifications. |
|
|
String |
Yes |
URL to which the customer is returned after the hosted transaction flow. |
Transaction object
|
Field |
Type |
Required |
Description |
|
|
String |
Yes |
Unique merchant transaction identifier. |
|
|
String |
Yes |
Transaction amount expressed in the lowest currency unit. |
|
|
String |
Yes |
Transaction currency. EUR and GBP are documented, depending on the merchant contract. |
|
|
String |
Yes |
Unique merchant transaction reference. |
Both transaction.id and transaction.reference must be unique.
|
Payment amount |
API value |
|
EUR 1.00 |
100 |
|
EUR 10.00 |
1000 |
|
GBP 25.50 |
2550 |
Client object
|
Field |
Type |
Required |
|
|
String |
Yes |
|
|
String |
Yes |
|
|
String |
Yes |
|
|
String |
No |
|
|
String |
No |
|
|
String |
No |
|
|
String |
No |
|
|
String |
No |
|
|
String |
No |
|
|
String |
No |
|
|
String |
No |
|
|
String |
No |
|
|
String |
No |
|
|
String |
No |
|
|
String |
No |
|
|
String |
No |
|
|
String |
No |
|
|
String |
No |
Account object
|
Field |
Type |
Required |
Description |
|
|
String |
Yes |
Customer identifier assigned by the merchant. Each identifier must be unique and paired with the customer for future transactions. |
Account-holder object
The account_holder object contains information about the bank account to debit and applies to relevant EUR payment flows.
|
Field |
Type |
Required |
Description |
|
|
String |
No |
Name on the account. |
|
|
String |
No |
Type of account. |
|
|
String |
Conditional |
IBAN of the account. Required when account_holder is included. |
|
|
String |
Conditional |
Bank identifier code. |
When the account_holder object is supplied, iban becomes mandatory. Providing the customer IBAN may simplify the EUR customer experience by allowing the bank-selection screen to be skipped.
Receive the API response
After the POST request is sent, the PaidBy API returns information about the created transaction, including the hosted redirect_url. The merchant backend should validate the HTTP response and required response fields before returning the redirect URL to the frontend.
Response example
JSON
{
"id": "e6988b4a-ed1c-4104-9caf-af6bb8769756",
"uid": "e6988b4a-ed1c-4104-9caf-af6bb8769756",
"secret": "159173ee-6309-4806-b499-d2598a2ed21e",
"context_uid": "e6988b4a-ed1c-4104-9caf-af6bb8769756",
"mode": "registration",
"original_message": {
"merchant_id": "Test_Merchant",
"transaction_id": "Test_ID",
"reference": "Test_Ref"
},
"transactions": "[]",
"state": "PENDING",
"compound_state": "PENDING.VALIDATED_TRANSACTION",
"redirect_url": "https://paidby.isxtech.com/landing/e6988b4a-ed1c-4104-9caf-af6bb8769756"
}
Following redirect_url opens the hosted transaction page.
Response-field reference
|
Field |
Type |
Description |
|
|
String |
Unique response identification code. |
|
|
String |
Unique response identification code. |
|
|
String |
Transaction secret that can be used to validate ISX notifications. |
|
|
String |
Context identifier associated with the transaction. |
|
|
String |
Transaction mode detected by ISX. |
|
|
Object |
Information from the original transaction request. |
|
|
String or collection |
Transaction data returned by the API. |
|
|
String |
Current state of the transaction. |
|
|
String |
Meaningful combined ISX transaction state. |
|
|
String |
Hosted URL used to continue the transaction flow. |
Original-message fields
|
Field |
Type |
Description |
|
|
String |
Merchant identifier from the request. |
|
|
String |
Merchant transaction ID from transaction.id. |
|
|
String |
Merchant transaction reference. |
Open the PaidBy transaction page
Use the redirect_url returned by the API response. Do not construct or hardcode a hosted transaction URL when a valid redirect_url has been returned.
JSON
{
"id": "e6988b4a-ed1c-4104-9caf-af6bb8769756",
"redirect_url": "https://paidby.isxtech.com/landing/e6988b4a-ed1c-4104-9caf-af6bb8769756"
}
- Browser redirect.
- New browser window.
- Hosted iframe or dialog, where supported by the merchant integration.
Backend integration
- Use the correct environment endpoint.
- Add the assigned From header.
- Add the assigned bearer token using Authorisation.
- Send the documented request objects.
- Ensure transaction.id and transaction.reference are unique.
- Store the returned transaction identifiers and secret securely.
- Return redirect_url to the frontend.
- Receive and validate transaction notifications.
- Confirm the final transaction state before fulfilling goods or services.
JavaScript
import express from "express";
const app = express();
app.use(express.json());
const PAIDBY_ENDPOINTS = {
stage: "https://stage-gateway.isignth.is/v1/authorization/",
production: "https://api.isxpay.com/gateway/service/v1/authorization/"
};
function getPaidByEndpoint() {
return process.env.PAIDBY_ENVIRONMENT === "production"
? PAIDBY_ENDPOINTS.production
: PAIDBY_ENDPOINTS.stage;
}
app.post("/api/create-paidby-transaction", async (req, res) => {
const { transactionId, reference, amount, currency,
firstName, lastName, email, accountIdentifier, accountHolder } = req.body;
const requestBody = {
workflow: process.env.PAIDBY_WORKFLOW,
merchant: {
id: process.env.PAIDBY_MERCHANT_ID,
transaction_webhook_url: process.env.PAIDBY_WEBHOOK_URL,
return_url: process.env.PAIDBY_RETURN_URL
},
client: { first_name: firstName, last_name: lastName, email },
transaction: { id: transactionId, amount: String(amount), currency, reference },
account: { identifier: accountIdentifier }
};
if (currency === "EUR" && accountHolder) {
requestBody.account_holder = {
name: accountHolder.name,
type: accountHolder.type,
iban: accountHolder.iban,
bic: accountHolder.bic
};
}
try {
const response = await fetch(getPaidByEndpoint(), {
method: "POST",
headers: {
From: process.env.PAIDBY_API_CLIENT_NAME,
Authorization: `Bearer ${process.env.PAIDBY_API_TOKEN}`,
"Content-Type": "application/json"
},
body: JSON.stringify(requestBody)
});
const data = await response.json();
if (!response.ok || typeof data.redirect_url !== "string") {
return res.status(502).json({ error: "Unable to create PaidBy transaction" });
}
return res.json({ id: data.id, uid: data.uid, redirect_url: data.redirect_url });
} catch (error) {
return res.status(500).json({ error: "Unexpected server error" });
}
});
app.listen(3000);
Environment configuration
PAIDBY_ENVIRONMENT=stage PAIDBY_API_CLIENT_NAME=YOUR_API_CLIENT_NAME PAIDBY_API_TOKEN=YOUR_API_TOKEN PAIDBY_WORKFLOW=YOUR_WORKFLOW PAIDBY_MERCHANT_ID=YOUR_MERCHANT_ID PAIDBY_WEBHOOK_URL=https://merchant.example.com/webhooks/paidby PAIDBY_RETURN_URL=https://merchant.example.com/payment/result
Frontend integration
- Send the transaction information to the merchant backend.
- Receive redirect_url.
- Open the hosted PaidBy transaction page.
- Display a clear error if transaction creation fails.
Redirect example
JavaScript
async function startPaidByPayment(paymentDetails) {
const response = await fetch("/api/create-paidby-transaction", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(paymentDetails)
});
const data = await response.json();
if (!response.ok || !data.redirect_url) {
throw new Error(data.error || "Unable to start payment");
}
window.location.assign(data.redirect_url);
}
Iframe dialog example
HTML & JavaScript
<dialog id="paidby-dialog">
<iframe
id="paidby-frame"
title="PaidBy Payment"
loading="lazy"
scrolling="yes"
allow="payment"
allow="camera; microphone"
src="about:blank">
</iframe>
</dialog>
const dialog = document.getElementById("paidby-dialog");
const iframe = document.getElementById("paidby-frame");
async function openPaidByDialog(paymentDetails) {
const response = await fetch("/api/create-paidby-transaction", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(paymentDetails)
});
const data = await response.json();
if (!response.ok || !data.redirect_url) {
throw new Error(data.error || "Unable to start payment");
}
iframe.src = data.redirect_url;
dialog.showModal();
}
dialog.addEventListener("close", () => {
iframe.src = "about:blank";
});
Do not place the PaidBy API token or merchant authentication headers in frontend JavaScript.
Changing language
A language code may be appended to the end of the redirect_url.
https://paidby.isxtech.com/landing/9ec923ef-3d70-410f-93c0-fe64df900353/fr
|
Code |
Language |
|
da |
Danish |
|
de |
German |
|
en |
English |
|
es |
Spanish |
|
fr |
French |
|
ja |
Japanese |
|
no |
Norwegian |
|
se |
Swedish |
Payment notifications
The merchant receives transaction event notifications through the configured transaction_webhook_url. For a successful transaction, the notification can include payment_provider_responses containing a provider_reference_code. Store this value because it may be required for reconciliation.
Visit PaidBy API Notifications
Visit Transaction Events and States
Transaction events & states
Final events
|
Event |
Description |
|
|
The transaction has been accepted and is being validated. |
|
|
The transaction has been declined. |
|
|
The transaction request has expired. |
|
|
The transaction has been cancelled. |
Additional events
|
Event |
Description |
|
|
Payment was successful. This is not a final transaction state. |
|
|
The transaction was automatically rejected due to risk rules. |
|
|
An unexpected error occurred and the transaction was halted. |
Do not treat payment_success alone as a final transaction result. Use final transaction events, states, notifications and backend verification before fulfilling goods or services.
Error handling
- Missing or invalid
Fromheader. - Missing or invalid
bearertoken. - Missing
Bearerprefix. - Invalid JSON.
- Missing required objects.
- Missing required client fields.
- Missing or duplicate
transaction.id. - Missing or duplicate
transaction.reference. - Invalid amount formatting.
- Unsupported currency.
- Missing
account.identifier. - Missing
account_holder.ibanwhenaccount_holderis included. - Non-successful HTTP responses.
- Non-JSON responses.
- Missing
redirect_url. - Transaction cancellation, expiration or rejection.
- Hosted-page loading failures.
- Notification-validation failures.
JSON
{
"error": {
"type": "paidby_transaction_error",
"message": "Unable to create PaidBy transaction"
}
}
⚠️ Do not expose API tokens, raw secrets, internal stack traces or complete upstream error responses to the customer.
HTTP response codes
PaidBy HTTP response codes are documented in the API Glossary.
Always inspect the HTTP status before processing the response body. A successful HTTP response should also be checked for id, uid, secret, state, compound_state and redirect_url. Receiving a redirect_url confirms that the hosted transaction flow can be opened; it does not confirm that the payment has completed successfully.