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).

  1. Create the session

    Hosted is the default mode. return_url and cancel_url are required.

    Node.jsts
    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.
    redirect(session.url!);

    Sessions stay open for 24 hours. Send an Idempotency-Key (the SDK does automatically) so a retried request cannot create two sessions; see Idempotency.

  2. Redirect the payer

    Send the browser to session.url with an HTTP 303 redirect from your server, or set window.location.href in 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.

  3. Handle the return

    On success Borga shows a confirmation for about two seconds and then redirects to return_url with session=ps_… appended as a query parameter. Read the session and branch on payment_status:

    Node.jsts
    // GET /order/complete?session=ps_…  (Next.js App Router route handler)
    export async function GET(request: Request) {
      const sessionId = new URL(request.url).searchParams.get("session");
      if (!sessionId) return new Response("Missing session", { status: 400 });
    
      const session = await borga.paymentSessions.retrieve(sessionId);
    
      switch (session.payment_status) {
        case "succeeded":
          return Response.redirect(`/thank-you?order=${session.id}`, 303);
        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 Response.redirect("/order/pending", 303);
        default:
          return Response.redirect("/order/failed", 303);
      }
    }

    Treat the return page as a status page. The authoritative signal is the payment.succeeded webhook, which also covers payers who never make it back to your site.

  4. Handle cancellation and failure

    If the payer uses the back link, Borga sends them to cancel_url unchanged. 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 to cancel_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.

FieldPurpose
amount, currencyWhat to charge. currency defaults to ISK.
return_url, cancel_urlWhere the payer lands afterwards. HTTPS on an allowed domain in live mode; http://localhost is fine in test mode.
external_referenceYour order or invoice number. Copied to the Payment and to webhook payloads so you can match them.
metadataAny JSON object. Copied to the Payment.
customer_emailPre-fills the email field and locks it.
customerAttach the payment to an existing Customer, needed for saved cards and subscriptions.
enabled_methodsRestrict or extend the methods shown. Default ["card", "apple_pay", "google_pay"]; add "bank_invoice" to offer krafa.
localeis (default) or en. Other language tags fall back to English.
save_payment_methodSave the card for later charges. See Saved cards.
subscriptionStart 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.

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.