Hosted checkout
Redirect the payer to a Borga-hosted page that handles cards, wallets, 3-D Secure and bank invoices.
Hosted checkout is the simplest integration and supports every payment method. Your server creates a payment session, you redirect the payer to its url on checkout.borga.is, Borga collects the payment, and the payer is sent back to your return_url. Card details never touch your servers, which keeps you in the lightest PCI scope (SAQ A).
Create the session
Hosted is the default mode. Give
return_urlandcancel_urltogether; without them the payer stays on Borga's confirmation page after paying, which suits a payment link sent by email or chat.Node.jsts// POST /checkout (Next.js App Router route handler) export async function POST() { const session = await borga.paymentSessions.create( { amount: 12900, currency: "ISK", customer_email: "anna@example.is", external_reference: "order_5678", return_url: "https://yoursite.is/order/complete", cancel_url: "https://yoursite.is/cart", enabled_methods: ["card", "apple_pay", "google_pay"], locale: "is", metadata: { order_id: "5678" }, }, // Your own idempotency key makes retries across processes safe too. { idempotencyKey: "order_5678_checkout" }, ); // Send the payer to the hosted page. session.url is absolute. return Response.redirect(session.url!, 303); }curlbashcurl https://api.borga.is/v1/payment_sessions \ -H "Authorization: Bearer sk_test_…" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: order_5678_checkout" \ -d '{ "amount": 12900, "currency": "ISK", "customer_email": "anna@example.is", "external_reference": "order_5678", "return_url": "https://yoursite.is/order/complete", "cancel_url": "https://yoursite.is/cart", "enabled_methods": ["card", "apple_pay", "google_pay"], "locale": "is", "metadata": { "order_id": "5678" } }'Sessions stay
openfor 24 hours. Send anIdempotency-Key(the SDK does automatically) so a retried request cannot create two sessions; see Idempotency.Redirect the payer
Send the browser to
session.urlwith an HTTP 303 redirect from your server, or setwindow.location.hrefin the browser. The payer sees your merchant name and logo, the amount, wallet buttons when available, the card form, and a bank-invoice tab if enabled. Line items are not shown; show the cart on your own page before redirecting.Handle the return
On success Borga shows a confirmation for about two seconds and then redirects to
return_urlwithsession=ps_…appended as a query parameter. Read the session and branch onpayment_status:Node.jsts// GET /order/complete?session=ps_… (Next.js App Router route handler) export async function GET(request: Request) { const url = new URL(request.url); const sessionId = url.searchParams.get("session"); if (!sessionId) return new Response("Missing session", { status: 400 }); const session = await borga.paymentSessions.retrieve(sessionId); // Response.redirect needs an absolute URL; resolve against the request. const to = (path: string) => Response.redirect(new URL(path, url), 303); switch (session.payment_status) { case "succeeded": return to(`/thank-you?order=${session.id}`); case "created": case "processing": // Bank invoices and slow 3-D Secure flows land here. Show a // "we're confirming your payment" page and finish on the webhook. return to("/order/pending"); default: return to("/order/failed"); } }Treat the return page as a status page. The authoritative signal is the
payment.succeededwebhook, which also covers payers who never make it back to your site.Handle cancellation and failure
If the payer uses the back link, Borga sends them to
cancel_urlunchanged. If a card is declined, the checkout shows the error and lets the payer try again; the session stays open. If the session expires, the page offers a link tocancel_url. In all of these cases no payment succeeded, and there is nothing to clean up on Borga's side.
Session options
The most useful fields. The full list is in the API reference.
| Field | Purpose |
|---|---|
amount, currency | What to charge. currency defaults to ISK. |
line_items | What the payment is for, line by line. Derives amount and becomes the invoice's lines; checkout shows only the total until payment, then itemises the confirmation and the receipt email. See Line items. |
return_url, cancel_url | Where the payer lands afterwards, both or neither. HTTPS on an allowed domain in live mode; http://localhost is fine in test mode. Without them checkout ends on its confirmation and offers no way back. |
external_reference | Your order or invoice number. Copied to the Payment and to webhook payloads so you can match them. |
metadata | Any JSON object. Copied to the Payment. |
customer_email | The payer's email. Stored on the session and the resulting Customer; checkout does not ask for it again. When it belongs to a VAT-exempt customer the session is priced without VAT; an email the payer types at checkout never changes the price. |
customer | Attach the payment to an existing Customer, needed for saved cards and subscriptions. |
enabled_methods | Restrict or extend the methods shown. Default ["card", "apple_pay", "google_pay"]; add "bank_invoice" to offer krafa. |
locale | is (default) or en. Other language tags fall back to English. |
save_payment_method | Save the card for later charges. See Saved cards. |
subscription | Start a subscription with these prices on success. See Subscriptions. |
Allowed redirect domains
Borga only redirects to domains you have registered, so a compromised integration cannot send payers to a phishing page. Add them under Settings → Account → Allowed redirect domains. Matching is on the hostname exactly, so list shop.example.is and www.shop.example.is separately if you use both. Attempts to use other domains fail at session creation with redirect_url_not_allowed.
Branding
The merchant name, logo and primary colour shown on the checkout come from Settings → Account. The page is served in Icelandic by default and in English when locale is en.
Payment links without code
Every session url is a shareable payment link valid for 24 hours. Creating sessions from a small internal tool, or straight from an invoicing workflow, is a common way to take payments by email or chat before building a full checkout.