Skip to main content

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.

Borga authenticates every API request using API keys. You include your secret key in the Authorization header of each request. Requests without a valid key are rejected before they reach any endpoint. There are two key types — one for server-side calls and one for browser-side flows — and you should never mix them up.
Never commit a secret key to source control, expose it in client-side JavaScript, or share it in a public channel. If a secret key is compromised, rotate it immediately from the dashboard under Settings → API Keys.

Key types

Borga issues two distinct key types, each with a different scope and environment variant.
Key prefixTypeWhere to use
sk_live_…Secret — live modeServer-side only. Processes real charges.
sk_test_…Secret — test modeServer-side only. No real charges.
pk_live_…Publishable — live modeBrowser-side embedded checkout only.
pk_test_…Publishable — test modeBrowser-side embedded checkout only.
Secret keys have full API access and must only ever appear in server-side code — environment variables, secrets managers, or backend configuration files. Publishable keys have a restricted scope limited to initiating embedded checkout sessions, making them safe to include in browser-side JavaScript.

Passing your secret key

Include your secret key as a Bearer token in the Authorization header of every request:
curl
curl --request GET \
  --url https://api.borga.is/v1/merchants/current \
  --header "Authorization: Bearer sk_test_YOUR_SECRET_KEY" \
  --header "X-Merchant-Id: mer_YOUR_MERCHANT_ID"
There is no separate login step or token exchange — the key itself is the credential.

Merchant ID header

Most Borga endpoints require an X-Merchant-Id header identifying which merchant account the request is for. Your Merchant ID has the format mer_… and is visible in the dashboard under Settings → API Keys. You can also retrieve it programmatically:
curl
curl --request GET \
  --url https://api.borga.is/v1/merchants/current \
  --header "Authorization: Bearer sk_test_YOUR_SECRET_KEY"
{
  "id": "mer_01HXYZ9876ABCDEF",
  "name": "Acme ehf.",
  "created_at": "2026-01-15T08:00:00Z"
}
The GET /v1/merchants/current endpoint does not require the X-Merchant-Id header — it infers the merchant from the API key itself. Use it to look up your Merchant ID during initial setup.
Set the Merchant ID as an environment variable alongside your secret key so both are available to your server at runtime:
BORGA_SECRET_KEY=sk_test_YOUR_SECRET_KEY
BORGA_MERCHANT_ID=mer_YOUR_MERCHANT_ID

Idempotency

Network failures can leave you uncertain whether a request was processed. To safely retry a POST request without risking duplicate charges, include an Idempotency-Key header with a unique string (a UUID works well). Borga stores the result of the first request and returns the same response for any subsequent requests with the same key, without executing the operation again.
curl
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 "Idempotency-Key: a1b2c3d4-e5f6-7890-abcd-ef1234567890" \
  --header "Content-Type: application/json" \
  --data '{
    "amount": 5000,
    "currency": "ISK",
    "description": "Order #1042"
  }'
Generate a fresh UUID for each distinct operation. Reusing the same key for a different payload will return the original response, not a new one — Borga deduplicates on the key alone, not the combination of key and body.

Test vs. live mode

The key prefix determines the mode of every request:
  • sk_test_… — test mode. No real charges are made. Card numbers, payments, and invoices are all simulated. Use this during development and staging.
  • sk_live_… — live mode. Requests process real ISK charges immediately.
You switch modes simply by swapping the key. No other configuration changes are required.

Authentication errors

HTTP statusMeaningWhat to do
401 UnauthorizedThe Authorization header is missing, malformed, or contains an invalid key.Verify the key is correct, has not been rotated, and is being passed as Bearer sk_… in the header.
403 ForbiddenThe key is valid but does not have permission to perform this action.Check that you are using a secret key (not a publishable key) for server-side calls, and that the key has the required scopes.
A 401 response body looks like this:
{
  "error": {
    "code": "unauthorized",
    "message": "Invalid API key provided."
  }
}
Inspect the error.message field for a human-readable explanation before contacting support.