---
title: "Integration Examples"
description: "Worked curl examples: authenticate, page through results, handle errors, verify a webhook."
url: "https://bareledger.app/guides/api-integration-examples"
category: "Developers & API"
updated: "2026-10-30"
publisher: "BareLedger (Syneria Technologies OPC)"
---

# Integration Examples

> Worked curl examples: authenticate, page through results, handle errors, verify a webhook.

Worked examples combining the conventions from [API Conventions](https://bareledger.app/guides/api-conventions), [API Authentication](https://bareledger.app/guides/api-authentication), and [Authorization](https://bareledger.app/guides/api-authorization). All examples use sanitized/placeholder values — substitute your own token and tenant id.

## 1. Log in and obtain a token

```bash
curl -X POST https://bareledger.app/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email": "user@example.com", "password": "<PASSWORD>"}'
```

Response (no 2FA enrolled):
```json
{
  "token": "<ACCESS_TOKEN>",
  "user": { "uuid": "...", "email": "user@example.com" }
}
```

If the account has 2FA enrolled, the response instead returns a challenge; resubmit with a `totp_code` field to receive the token.

## 2. Make an authenticated, tenant-scoped request

```bash
curl https://bareledger.app/api/v1/journals?status=submitted \
  -H "Authorization: Bearer <ACCESS_TOKEN>" \
  -H "X-Tenant: <TENANT_UUID>"
```

`X-Tenant` is required on every tenant-scoped endpoint — omitting it, or sending one you don't belong to, returns `409`.

## 3. Create a resource and handle validation errors

```bash
curl -X POST https://bareledger.app/api/v1/journals \
  -H "Authorization: Bearer <ACCESS_TOKEN>" \
  -H "X-Tenant: <TENANT_UUID>" \
  -H "Content-Type: application/json" \
  -d '{
    "transaction_date": "2026-08-01",
    "currency": "PHP",
    "lines": [
      { "account_id": "<ACCOUNT_UUID_1>", "debit": 1000.00, "credit": 0 },
      { "account_id": "<ACCOUNT_UUID_2>", "debit": 0, "credit": 1000.00 }
    ]
  }'
```

A validation failure (e.g. unbalanced lines on submit, not on draft save) returns:
```json
422 Unprocessable Entity
{
  "message": "The given data was invalid.",
  "errors": { "lines": ["Total debits must equal total credits."] }
}
```

## 4. Handle pagination

Pass `page` and `per_page` to get one page and a `meta` block; keep requesting the next page until `current_page` reaches `last_page`. Without them, most lists return every matching row.

```bash
curl "https://bareledger.app/api/v1/invoices?page=2&per_page=25" \
  -H "Authorization: Bearer <ACCESS_TOKEN>" \
  -H "X-Tenant: <TENANT_UUID>"
```
```json
{ "data": [ /* 25 items */ ], "meta": { "current_page": 2, "last_page": 6, "per_page": 25, "total": 137 } }
```

## 5. Handle a permission denial

```json
403 Forbidden
{ "message": "You do not have permission to perform this action.", "permission": "sales.approve" }
```
The `permission` field tells you exactly which key was missing — useful for surfacing a precise "you need X permission" message in a client app rather than a generic error.

## 6. Handle a lapsed subscription

```json
402 Payment Required
{ "message": "An active subscription is required to perform this action." }
```
Reads and `*/billing/*` endpoints remain available even in this state — a client can still show data and offer a way to resubscribe.

## 7. Verify a billing webhook (server-side integration pattern)

Both Paddle and PayMongo webhooks are verified via HMAC signature, not a bearer token — see Integration — Paddle / Integration — PayMongo for the exact header names and algorithm. Pseudocode:
```python
import hmac, hashlib

def verify(raw_body: bytes, signature_header: str, secret: str) -> bool:
    expected = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, signature_header)
```
Never trust a webhook payload whose signature doesn't verify — both gateways fail closed in this system's own implementation, and any external consumer replicating similar logic should do the same.
