> ## Documentation Index
> Fetch the complete documentation index at: https://docs.borga.is/llms.txt
> Use this file to discover all available pages before exploring further.

# Accept a payment with the Borga API

> Walk through creating a customer, creating a payment, and confirming success using the Borga API — from first request to verified charge.

This guide covers the complete lifecycle of a one-time payment: creating a customer record, creating a payment object, routing the customer through a hosted checkout session, and confirming the charge succeeded on return. By the end you will have a working end-to-end flow that you can adapt for any e-commerce or service billing scenario.

<Note>
  Borga amounts are expressed in whole Icelandic króna (ISK). ISK has no subunit — pass `5990` to charge 5,990 kr, not 59.90 kr.
</Note>

<Steps>
  <Step title="Create a customer (optional)">
    Creating a customer record before charging lets you attach payment history, save payment methods, and link subscriptions or invoices to a single identity. If you do not yet have a customer in Borga, create one now.

    <CodeGroup>
      ```bash curl theme={null}
      curl --request POST \
        --url https://api.borga.is/v1/customers \
        --header "Authorization: Bearer sk_test_YOUR_SECRET_KEY" \
        --header "X-Merchant-Id: mer_YOUR_MERCHANT_ID" \
        --header "Content-Type: application/json" \
        --data '{
          "email": "buyer@example.is",
          "name": "Jón Jónsson"
        }'
      ```

      ```javascript Node.js theme={null}
      const customer = await fetch('https://api.borga.is/v1/customers', {
        method: 'POST',
        headers: {
          'Authorization': 'Bearer sk_test_YOUR_SECRET_KEY',
          'X-Merchant-Id': 'mer_YOUR_MERCHANT_ID',
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          email: 'buyer@example.is',
          name: 'Jón Jónsson',
        }),
      }).then(r => r.json());

      console.log(customer.id); // cus_01HXYZ…
      ```
    </CodeGroup>

    Save the returned `id` (e.g. `cus_01HXYZ…`). You will pass it as the `customer` field in subsequent requests to link activity to this person.
  </Step>

  <Step title="Create a payment">
    A payment object represents a single charge attempt. Create one with the amount to collect, the currency, and an optional description that will appear on the invoice.

    <CodeGroup>
      ```bash curl theme={null}
      curl --request POST \
        --url https://api.borga.is/v1/payments \
        --header "Authorization: Bearer sk_test_YOUR_SECRET_KEY" \
        --header "X-Merchant-Id: mer_YOUR_MERCHANT_ID" \
        --header "Content-Type: application/json" \
        --data '{
          "amount": 5990,
          "currency": "ISK",
          "customer": "cus_01HXYZ",
          "description": "Order #1234",
          "external_reference": "order_1234"
        }'
      ```

      ```javascript Node.js theme={null}
      const payment = await fetch('https://api.borga.is/v1/payments', {
        method: 'POST',
        headers: {
          'Authorization': 'Bearer sk_test_YOUR_SECRET_KEY',
          'X-Merchant-Id': 'mer_YOUR_MERCHANT_ID',
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          amount: 5990,
          currency: 'ISK',
          customer: 'cus_01HXYZ',
          description: 'Order #1234',
          external_reference: 'order_1234',
        }),
      }).then(r => r.json());

      console.log(payment.id); // pay_01HXYZ…
      ```
    </CodeGroup>

    A successful response returns the payment object with a `pending` status:

    ```json theme={null}
    {
      "id": "pay_01HXYZ1234ABCDEF",
      "status": "pending",
      "amount": 5990,
      "currency": "ISK",
      "customer": "cus_01HXYZ",
      "description": "Order #1234",
      "external_reference": "order_1234",
      "created_at": "2026-04-29T10:00:00Z"
    }
    ```

    Save the `id`. You will attach it to a payment session in the next step and poll it after checkout to confirm success.

    <Tip>
      Store your internal order ID in the `external_reference` field. It is indexed, so you can look up the Borga payment from your own system without needing to track the Borga `id` separately.
    </Tip>
  </Step>

  <Step title="Create a payment session">
    A payment session hosts the checkout UI and handles 3D Secure redirects for you. Pass the payment `id` you just created so the session is linked to it, and provide a `return_url` where Borga will send the customer after checkout.

    <CodeGroup>
      ```bash curl theme={null}
      curl --request POST \
        --url https://api.borga.is/v1/payment_sessions \
        --header "Authorization: Bearer sk_test_YOUR_SECRET_KEY" \
        --header "X-Merchant-Id: mer_YOUR_MERCHANT_ID" \
        --header "Content-Type: application/json" \
        --data '{
          "payment": "pay_01HXYZ1234ABCDEF",
          "mode": "hosted",
          "return_url": "https://yoursite.is/order/complete?payment_id=pay_01HXYZ1234ABCDEF",
          "cancel_url": "https://yoursite.is/cart",
          "customer": "cus_01HXYZ",
          "locale": "is"
        }'
      ```

      ```javascript Node.js theme={null}
      const session = await fetch('https://api.borga.is/v1/payment_sessions', {
        method: 'POST',
        headers: {
          'Authorization': 'Bearer sk_test_YOUR_SECRET_KEY',
          'X-Merchant-Id': 'mer_YOUR_MERCHANT_ID',
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          payment: 'pay_01HXYZ1234ABCDEF',
          mode: 'hosted',
          return_url: 'https://yoursite.is/order/complete?payment_id=pay_01HXYZ1234ABCDEF',
          cancel_url: 'https://yoursite.is/cart',
          customer: 'cus_01HXYZ',
          locale: 'is',
        }),
      }).then(r => r.json());

      console.log(session.url); // https://checkout.borga.is/…
      ```
    </CodeGroup>

    The response includes a `url` property pointing to the hosted checkout page on `checkout.borga.is`.
  </Step>

  <Step title="Redirect the customer">
    Redirect the customer's browser to `session.url`. Borga's hosted checkout page handles all payment method presentation — cards, Apple Pay, Google Pay, and krafa — without any additional code on your side.

    ```javascript Node.js (Express) theme={null}
    // After creating the session server-side, redirect the browser
    res.redirect(session.url);
    ```

    When the customer completes or abandons checkout, Borga redirects them back to the `return_url` or `cancel_url` you specified.
  </Step>

  <Step title="Confirm success">
    On the page that handles your `return_url`, retrieve the payment to verify its status before fulfilling the order.

    <CodeGroup>
      ```bash curl theme={null}
      curl --request GET \
        --url https://api.borga.is/v1/payments/pay_01HXYZ1234ABCDEF \
        --header "Authorization: Bearer sk_test_YOUR_SECRET_KEY" \
        --header "X-Merchant-Id: mer_YOUR_MERCHANT_ID"
      ```

      ```javascript Node.js theme={null}
      const payment = await fetch(
        'https://api.borga.is/v1/payments/pay_01HXYZ1234ABCDEF',
        {
          headers: {
            'Authorization': 'Bearer sk_test_YOUR_SECRET_KEY',
            'X-Merchant-Id': 'mer_YOUR_MERCHANT_ID',
          },
        }
      ).then(r => r.json());

      if (payment.status === 'succeeded') {
        // Fulfil the order
      }
      ```
    </CodeGroup>

    A confirmed charge returns a `status` of `"succeeded"`:

    ```json theme={null}
    {
      "id": "pay_01HXYZ1234ABCDEF",
      "status": "succeeded",
      "amount": 5990,
      "currency": "ISK",
      "description": "Order #1234"
    }
    ```

    <Warning>
      Do not fulfil the order based solely on the `return_url` redirect. The customer's browser could be manipulated. Always fetch the payment server-side and check `status === "succeeded"` before fulfilling. For production integrations, use [webhooks](/guides/webhooks) to receive asynchronous confirmation.
    </Warning>
  </Step>
</Steps>

## Issue a refund

If you need to refund a succeeded payment, use `POST /v1/refunds`. Omit `amount` to refund the full charge.

```bash curl theme={null}
curl --request POST \
  --url https://api.borga.is/v1/refunds \
  --header "Authorization: Bearer sk_test_YOUR_SECRET_KEY" \
  --header "X-Merchant-Id: mer_YOUR_MERCHANT_ID" \
  --header "Content-Type: application/json" \
  --data '{
    "payment": "pay_01HXYZ1234ABCDEF",
    "amount": 5990,
    "reason": "customer_request"
  }'
```

Borga automatically generates a credit note linked to the original invoice when a refund is issued.

## Next steps

* [Hosted checkout](/guides/hosted-checkout) — configure the checkout page appearance, locale, and payment methods
* [Webhooks](/guides/webhooks) — receive asynchronous `payment.succeeded` and `payment.failed` events
* [Subscriptions](/guides/subscriptions) — set up recurring billing for the same customer
