API overview
Conventions shared by every endpoint: base URL, authentication, request and response format, ids, metadata and versioning.
https://api.borga.is
The Borga API is REST over HTTPS with JSON bodies. It follows the conventions most developers know from Stripe: predictable resource URLs, snake_case fields, prefixed ids, cursor pagination and idempotent POSTs. Where Borga's domain differs, for example bank invoices and accounting sync, the API says so rather than bending the concept.
Authentication
Send a secret key as a bearer token. The key identifies your merchant and its mode; nothing else is needed.
Authorization: Bearer sk_test_…Publishable keys (pk_…) may only call POST /v1/payment_sessions with mode: "embedded", from an allowed origin. Everything else needs a secret key. See Authentication.
Requests
- Bodies are JSON with
Content-Type: application/json. - Amounts are integers in the currency's smallest unit. ISK has none, so
1990is 1.990 kr.; euro uses cents. Supported currencies:ISK(no minor unit),EUR,USD,GBP,DKK,NOK,SEK - Timestamps are ISO 8601 strings in UTC, for example
2026-09-07T12:04:31.512Z. - Unknown fields are ignored; wrong types return
validation_failed. - POST requests should carry an
Idempotency-Key. See Idempotency.
Responses
Objects are returned as flat JSON with related objects referenced by id ("customer": "cus_…"). A few objects carry an object field naming their type; most do not, so key off the id prefix instead. Lists come back as { "data": [...], "has_more": true }; see Pagination.
Every response includes an X-Request-Id header. Errors share one envelope with type, code, message, optional param, doc_url and request_id; see Errors.
Object ids
Ids are random strings with a type prefix, so a pay_… is always a payment wherever it shows up.
| Prefix | Object |
|---|---|
pay_ | Payment |
ps_ | Payment session |
pm_ | Payment method (saved card) |
ref_ | Refund |
cus_ | Customer |
cprt_ | Customer portal link |
prod_ | Product |
price_ | Price |
sub_ | Subscription |
si_ | Subscription item |
inv_ | Invoice |
ili_ | Invoice line |
ii_ | Invoice item (one-off charge) |
cn_ | Credit note |
mtr_ | Meter |
ue_ | Usage event |
cmt_ | Customer meter balance |
evt_ | Webhook event |
we_ | Webhook endpoint |
merch_ | Merchant |
key_ | API key |
al_ | Accounting connection |
be_ | Billing ledger entry |
pcs_ | Payment session client secret (embedded checkout, returned once) |
sk_test_ / sk_live_ | Secret API key |
pk_test_ / pk_live_ | Publishable API key |
Metadata
Most objects accept a metadata object of your own keys and values. Borga stores it and returns it unchanged, never interprets it, and copies it from a payment session to the payment it creates. Use it for order numbers, internal ids and anything you want to see in webhooks.
Test and live
Mode is a property of the key. Test objects and live objects never mix, and live keys only work after going live. Everything on these pages behaves identically in both modes.
Versioning
The API is versioned in the path (/v1). Backwards-compatible changes (new fields, new endpoints, new event types, new error codes) ship without notice. Breaking changes would get a new path version with a migration period. Write clients to ignore fields and codes they do not recognise.
Dashboard-only configuration
API keys, webhook endpoints, allowed redirect domains, the accounting connection and bank-invoice settings are managed in the dashboard, not through API keys. Calling those routes with an API key returns wrong_auth_method.