{
    "info": {
        "_postman_id": "ad7b5ecc-a42c-47d9-8bfb-22f61be81344",
        "name": "HassleFreeBooks API v1",
        "description": "Every operation of the HassleFreeBooks API, generated from its OpenAPI document (collection 1.0.3).\n\n1. Select the **HassleFreeBooks** environment (or edit the collection variables).\n2. Either paste an API key from https://hasslefreebooks.com/api-keys into `accessToken`, or run **Authentication → User Login** with `email` and `password` set in the environment: it stores `accessToken` and `refreshToken` for you.\n3. Run anything else. **Refresh Access Token** trades `refreshToken` for a new pair (single-use: it stores the new one).\n\nEvery response is `{ok, request_id, data | error, meta}`. Full reference: https://hasslefreebooks.com/docs/api",
        "version": "1.0.3",
        "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
    },
    "auth": {
        "type": "bearer",
        "bearer": [
            {
                "key": "token",
                "value": "{{accessToken}}",
                "type": "string"
            }
        ]
    },
    "event": [
        {
            "listen": "test",
            "script": {
                "type": "text/javascript",
                "exec": [
                    "pm.test('Response is the HassleFreeBooks envelope', function () {",
                    "    const ct = pm.response.headers.get('Content-Type') || '';",
                    "    if (!ct.includes('application/json')) { return; }",
                    "    pm.expect(pm.response.json()).to.have.property('ok');",
                    "});"
                ]
            }
        }
    ],
    "variable": [
        {
            "key": "baseUrl",
            "value": "https://hasslefreebooks.com",
            "type": "string"
        },
        {
            "key": "accessToken",
            "value": "",
            "type": "string"
        },
        {
            "key": "refreshToken",
            "value": "",
            "type": "string"
        }
    ],
    "item": [
        {
            "name": "System",
            "description": "System health, deprecation notices, documentation, and public contact form.\nThese endpoints do not require authentication.",
            "item": [
                {
                    "name": "Public Contact Form",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/contact",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "contact"
                            ]
                        },
                        "description": "Submit a public contact form message. No authentication required.\n\nPublic: no token. Operation: `submitContactForm`.",
                        "auth": {
                            "type": "noauth"
                        },
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"name\": \"\",\n    \"email\": \"user@example.com\",\n    \"message\": \"\"\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Deprecation Notices",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/deprecation",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "deprecation"
                            ]
                        },
                        "description": "Get a list of deprecated API features and migration guidance. No authentication required.\n\nPublic: no token. Operation: `getDeprecationNotices`.",
                        "auth": {
                            "type": "noauth"
                        }
                    },
                    "response": []
                },
                {
                    "name": "OpenAPI Specification (JSON)",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/docs",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "docs"
                            ]
                        },
                        "description": "Returns the OpenAPI v1 specification in JSON format. No authentication required.\n\nPublic: no token. Operation: `getDocsJson`.",
                        "auth": {
                            "type": "noauth"
                        }
                    },
                    "response": []
                },
                {
                    "name": "API Health Check",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/health",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "health"
                            ]
                        },
                        "description": "Check the health status of the API. No authentication required.\n\nPublic: no token. Operation: `healthCheck`.",
                        "auth": {
                            "type": "noauth"
                        }
                    },
                    "response": []
                },
                {
                    "name": "OpenAPI Specification (format negotiation)",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/openapi",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "openapi"
                            ],
                            "query": [
                                {
                                    "key": "format",
                                    "value": "json",
                                    "description": "Response format (json or yaml)",
                                    "disabled": true
                                }
                            ]
                        },
                        "description": "Returns the OpenAPI v1 specification. Supports format negotiation via `?format=yaml` or `?format=json`.\nDefaults to JSON.\n\nPublic: no token. Operation: `getOpenApiSpec`.",
                        "auth": {
                            "type": "noauth"
                        }
                    },
                    "response": []
                },
                {
                    "name": "Validate OpenAPI Specification",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/openapi/validate",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "openapi",
                                "validate"
                            ]
                        },
                        "description": "Validates the structure of the OpenAPI specification and returns validation results. No authentication required.\n\nPublic: no token. Operation: `validateOpenApiSpec`.",
                        "auth": {
                            "type": "noauth"
                        }
                    },
                    "response": []
                }
            ]
        },
        {
            "name": "Authentication",
            "description": "User authentication and token management. Includes signup, login, password reset,\ntoken refresh, and logout. Access tokens expire in 1 hour; refresh tokens in 7 days.",
            "item": [
                {
                    "name": "User Login",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/auth/login",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "auth",
                                "login"
                            ]
                        },
                        "description": "Authenticate with email and password. On success `data.tokens` holds the access token and the refresh token, and\n`data.user_id` the user.\n\n* An address whose email is not yet verified is refused: 403 `EMAIL_NOT_VERIFIED`.\n* An account with two-factor authentication answers 200 with `data.mfa_required: true`, `data.mfa_method` and a short-lived\n  `data.mfa_token` instead of tokens; send the token and the code to `POST /api/v1/auth/mfa/verify`.\n* A wrong password and an unknown address are the same 401 `INVALID_CREDENTIALS`, so the response does not reveal which\n  addresses have an account.\n* Limited to 10 attempts a minute per client IP (429 `RATE_LIMIT_EXCEEDED`).\n\nFor a server-to-server integration prefer an API key: it needs no login, no refresh and no second factor.\n\nPublic: no token. Operation: `login`.",
                        "auth": {
                            "type": "noauth"
                        },
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"email\": \"{{email}}\",\n    \"password\": \"{{password}}\"\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": [],
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "const body = pm.response.headers.get('Content-Type') && pm.response.headers.get('Content-Type').includes('json') ? pm.response.json() : null;",
                                    "const tokens = body && body.ok && body.data && body.data.tokens;",
                                    "if (tokens && tokens.access_token) {",
                                    "    pm.collectionVariables.set('accessToken', tokens.access_token);",
                                    "    if (tokens.refresh_token) { pm.collectionVariables.set('refreshToken', tokens.refresh_token); }",
                                    "    if (pm.environment.has('accessToken')) { pm.environment.set('accessToken', tokens.access_token); }",
                                    "    if (tokens.refresh_token && pm.environment.has('refreshToken')) { pm.environment.set('refreshToken', tokens.refresh_token); }",
                                    "}"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "User Logout",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/auth/logout",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "auth",
                                "logout"
                            ]
                        },
                        "description": "End the session: the access token used for this call and its refresh token stop working at once. API keys are not affected; revoke those with `DELETE /api/v1/keys/{id}`.\n\nScope: `read`. Operation: `logout`."
                    },
                    "response": []
                },
                {
                    "name": "Resend MFA SMS Code",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/auth/mfa/resend",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "auth",
                                "mfa",
                                "resend"
                            ]
                        },
                        "description": "Resend the SMS verification code for multi-factor authentication.\nRequires a valid `mfa_token` from the login response.\nSubject to rate limiting to prevent SMS abuse.\n\nPublic: no token. Operation: `resendMfaSms`.",
                        "auth": {
                            "type": "noauth"
                        },
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"mfa_token\": \"mfa_abc123xyz\"\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": [],
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "const body = pm.response.headers.get('Content-Type') && pm.response.headers.get('Content-Type').includes('json') ? pm.response.json() : null;",
                                    "const tokens = body && body.ok && body.data && body.data.tokens;",
                                    "if (tokens && tokens.access_token) {",
                                    "    pm.collectionVariables.set('accessToken', tokens.access_token);",
                                    "    if (tokens.refresh_token) { pm.collectionVariables.set('refreshToken', tokens.refresh_token); }",
                                    "    if (pm.environment.has('accessToken')) { pm.environment.set('accessToken', tokens.access_token); }",
                                    "    if (tokens.refresh_token && pm.environment.has('refreshToken')) { pm.environment.set('refreshToken', tokens.refresh_token); }",
                                    "}"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "Verify MFA Code",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/auth/mfa/verify",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "auth",
                                "mfa",
                                "verify"
                            ]
                        },
                        "description": "Verify a multi-factor authentication code during the API login flow.\nUses a short-lived `mfa_token` (not a bearer token) obtained from the\nlogin response when MFA is required. On success returns access and refresh tokens.\n\nPublic: no token. Operation: `verifyMfa`.",
                        "auth": {
                            "type": "noauth"
                        },
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"mfa_token\": \"mfa_abc123xyz\",\n    \"code\": \"123456\"\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": [],
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "const body = pm.response.headers.get('Content-Type') && pm.response.headers.get('Content-Type').includes('json') ? pm.response.json() : null;",
                                    "const tokens = body && body.ok && body.data && body.data.tokens;",
                                    "if (tokens && tokens.access_token) {",
                                    "    pm.collectionVariables.set('accessToken', tokens.access_token);",
                                    "    if (tokens.refresh_token) { pm.collectionVariables.set('refreshToken', tokens.refresh_token); }",
                                    "    if (pm.environment.has('accessToken')) { pm.environment.set('accessToken', tokens.access_token); }",
                                    "    if (tokens.refresh_token && pm.environment.has('refreshToken')) { pm.environment.set('refreshToken', tokens.refresh_token); }",
                                    "}"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "Reset Password (alias)",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/auth/password-reset/confirm",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "auth",
                                "password-reset",
                                "confirm"
                            ]
                        },
                        "description": "Alias for `/auth/password/reset`. Resets the user's password using a valid token.\nNo authentication required.\n\nPublic: no token. Operation: `passwordResetConfirm`.",
                        "auth": {
                            "type": "noauth"
                        },
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"token\": \"abc123def456...\",\n    \"new_password\": \"newSecurePassword123\"\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Request Password Reset (alias)",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/auth/password-reset/request",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "auth",
                                "password-reset",
                                "request"
                            ]
                        },
                        "description": "Alias for `/auth/password/forgot`. Sends a password reset link to the provided email.\nAlways returns success to prevent email enumeration. No authentication required.\n\nPublic: no token. Operation: `passwordResetRequest`.",
                        "auth": {
                            "type": "noauth"
                        },
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"email\": \"user@example.com\"\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Request Password Reset",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/auth/password/forgot",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "auth",
                                "password",
                                "forgot"
                            ]
                        },
                        "description": "Request a password reset token. Sends a reset link to the provided email address\nif an account exists. Always returns success to prevent email enumeration.\nNo authentication required.\n\nPublic: no token. Operation: `forgotPassword`.",
                        "auth": {
                            "type": "noauth"
                        },
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"email\": \"user@example.com\"\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Reset Password",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/auth/password/reset",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "auth",
                                "password",
                                "reset"
                            ]
                        },
                        "description": "Reset the user's password using a valid reset token received via email.\nThe token is single-use and expires after a configured time window.\nNo authentication required.\n\nPublic: no token. Operation: `resetPassword`.",
                        "auth": {
                            "type": "noauth"
                        },
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"token\": \"abc123def456...\",\n    \"new_password\": \"newSecurePassword123\"\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Refresh Access Token",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/auth/refresh",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "auth",
                                "refresh"
                            ]
                        },
                        "description": "Exchange the refresh token for a new access token **and a new refresh token**.\n\nRefresh tokens are single-use and rotated (`refresh_token_rotated: true`): store the `refresh_token` this response returns\nand discard the one you sent. The new token keeps the original seven-day expiry; rotation never extends it. Presenting an\nalready-exchanged refresh token again is treated as theft: every token issued from that sign-in is revoked and the call\nanswers 401 `REFRESH_TOKEN_REUSED`, so the holder must sign in again. The only exception is a retry within a few seconds\nof the rotation (a lost response), which is exchanged normally. Each refresh also revokes the access token it replaces, so\nprocesses that share one login must share the refreshed tokens; several workers should each use an API key instead.\n\nPublic: no token. Operation: `refreshToken`.",
                        "auth": {
                            "type": "noauth"
                        },
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"refresh_token\": \"{{refreshToken}}\"\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": [],
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "const body = pm.response.headers.get('Content-Type') && pm.response.headers.get('Content-Type').includes('json') ? pm.response.json() : null;",
                                    "const tokens = body && body.ok && body.data && body.data.tokens;",
                                    "if (tokens && tokens.access_token) {",
                                    "    pm.collectionVariables.set('accessToken', tokens.access_token);",
                                    "    if (tokens.refresh_token) { pm.collectionVariables.set('refreshToken', tokens.refresh_token); }",
                                    "    if (pm.environment.has('accessToken')) { pm.environment.set('accessToken', tokens.access_token); }",
                                    "    if (tokens.refresh_token && pm.environment.has('refreshToken')) { pm.environment.set('refreshToken', tokens.refresh_token); }",
                                    "}"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "Create Account (alias)",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/auth/register",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "auth",
                                "register"
                            ]
                        },
                        "description": "Alias for `/auth/signup`. Registers a new user account. Creates the user, an initial\nentity (workspace), and an owner membership. Identical behavior to `/auth/signup`.\nNo authentication required.\n\nPublic: no token. Operation: `authRegister`.",
                        "auth": {
                            "type": "noauth"
                        },
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"email\": \"newuser@example.com\",\n    \"password\": \"securepassword123\",\n    \"entity_name\": \"My Business\",\n    \"accept_terms\": true\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": [],
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "const body = pm.response.headers.get('Content-Type') && pm.response.headers.get('Content-Type').includes('json') ? pm.response.json() : null;",
                                    "const tokens = body && body.ok && body.data && body.data.tokens;",
                                    "if (tokens && tokens.access_token) {",
                                    "    pm.collectionVariables.set('accessToken', tokens.access_token);",
                                    "    if (tokens.refresh_token) { pm.collectionVariables.set('refreshToken', tokens.refresh_token); }",
                                    "    if (pm.environment.has('accessToken')) { pm.environment.set('accessToken', tokens.access_token); }",
                                    "    if (tokens.refresh_token && pm.environment.has('refreshToken')) { pm.environment.set('refreshToken', tokens.refresh_token); }",
                                    "}"
                                ]
                            }
                        }
                    ]
                },
                {
                    "name": "Create Account",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/auth/signup",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "auth",
                                "signup"
                            ]
                        },
                        "description": "Register a new user account. Creates the user, an initial entity (workspace),\nand an owner membership. Triggers an email verification flow.\nNo authentication required.\n\nPublic: no token. Operation: `authSignup`.",
                        "auth": {
                            "type": "noauth"
                        },
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"email\": \"newuser@example.com\",\n    \"password\": \"securepassword123\",\n    \"entity_name\": \"My Business\",\n    \"accept_terms\": true\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": [],
                    "event": [
                        {
                            "listen": "test",
                            "script": {
                                "type": "text/javascript",
                                "exec": [
                                    "const body = pm.response.headers.get('Content-Type') && pm.response.headers.get('Content-Type').includes('json') ? pm.response.json() : null;",
                                    "const tokens = body && body.ok && body.data && body.data.tokens;",
                                    "if (tokens && tokens.access_token) {",
                                    "    pm.collectionVariables.set('accessToken', tokens.access_token);",
                                    "    if (tokens.refresh_token) { pm.collectionVariables.set('refreshToken', tokens.refresh_token); }",
                                    "    if (pm.environment.has('accessToken')) { pm.environment.set('accessToken', tokens.access_token); }",
                                    "    if (tokens.refresh_token && pm.environment.has('refreshToken')) { pm.environment.set('refreshToken', tokens.refresh_token); }",
                                    "}"
                                ]
                            }
                        }
                    ]
                }
            ]
        },
        {
            "name": "User",
            "description": "Authenticated user profile and dashboard data. Returns user information,\nactive entity context, and composite dashboard summaries.",
            "item": [
                {
                    "name": "List Invitations",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/invitations",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "invitations"
                            ],
                            "query": [
                                {
                                    "key": "status",
                                    "value": "pending",
                                    "description": "Only invitations in this state.",
                                    "disabled": true
                                },
                                {
                                    "key": "limit",
                                    "value": "50",
                                    "description": "Rows to return.",
                                    "disabled": true
                                }
                            ]
                        },
                        "description": "List all pending and accepted invitations for the current entity.\n\nScope: `read`. Roles: owner. Operation: `listInvitations`."
                    },
                    "response": []
                },
                {
                    "name": "Send User Invitation",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/invitations",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "invitations"
                            ]
                        },
                        "description": "Send an invitation to join an entity. Creates a SHA-256 hashed token.\n\nScope: `write`. Roles: owner. Operation: `sendInvitation`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"email\": \"user@example.com\",\n    \"role_key\": \"\"\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Revoke Invitation",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/invitations/revoke",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "invitations",
                                "revoke"
                            ]
                        },
                        "description": "Revoke a pending invitation by ID. Only the entity owner may revoke invitations.\n\nScope: `write`. Roles: owner. Operation: `revokeInvitation`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"invitation_id\": 0\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Get Current User",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/me",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "me"
                            ]
                        },
                        "description": "Retrieve information about the currently authenticated user.\n\nScope: `read`. Operation: `getCurrentUser`."
                    },
                    "response": []
                }
            ]
        },
        {
            "name": "ChartOfAccounts",
            "description": "Chart of accounts CRUD operations. Supports creating, listing, updating,\nand deactivating (soft-delete) accounts. Accounts are entity-scoped.",
            "item": [
                {
                    "name": "List chart of accounts",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/accounts",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "accounts"
                            ],
                            "query": [
                                {
                                    "key": "entity_id",
                                    "value": "",
                                    "description": "Defaults to the caller's active entity.",
                                    "disabled": true
                                }
                            ]
                        },
                        "description": "Returns the entity's chart of accounts. Alias of `/api/v1/coa` with an\nidentical payload; the list appears under both `coa_entries` and\n`accounts`.\n\nScope: `read`. Operation: `listAccounts`."
                    },
                    "response": []
                },
                {
                    "name": "List Accounts",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/coa",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "coa"
                            ],
                            "query": [
                                {
                                    "key": "entity_id",
                                    "value": "",
                                    "description": "Act on this entity instead of the caller's active one; the caller must be a member.",
                                    "disabled": true
                                }
                            ]
                        },
                        "description": "Every active account in the chart of accounts for the authenticated\nuser's active entity.\n\nNot paginated and not searchable. This used to document page, per_page,\nsearch and is_active, and a data.pagination block; the handler calls\n`COA::getAll($entityId)` — `WHERE entity_id = ? AND is_active = 1`, no\nLIMIT — so those parameters were silently ignored and page 2 returned\npage 1. A chart of accounts is bounded (hundreds of rows), so the list is\nreturned whole rather than paginated.\n\nThe same payload is served at `/api/v1/accounts`, where the rows also\nappear under `accounts` for the Flutter client. `include_inactive` on\nthat alias is likewise not implemented — deactivated accounts are never\nreturned.\n\nScope: `read`. Operation: `coaList`."
                    },
                    "response": []
                },
                {
                    "name": "Create Account",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/coa",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "coa"
                            ]
                        },
                        "description": "Create a new account in the chart of accounts for the authenticated\nuser's active entity.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `coaCreate`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"name\": \"Office Supplies\",\n    \"code\": \"6100\",\n    \"type\": \"expense\",\n    \"subtype\": \"operating_expense\"\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Delete Account",
                    "request": {
                        "method": "DELETE",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/coa/:id",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "coa",
                                ":id"
                            ],
                            "variable": [
                                {
                                    "key": "id",
                                    "value": "1",
                                    "description": "Account ID"
                                }
                            ]
                        },
                        "description": "Soft-delete (deactivate) an account from the chart of accounts.\nAccounts with existing transaction lines cannot be hard-deleted, and an\naccount whose lines do not net to zero cannot be deactivated (409).\n\nScope: `write`. Roles: owner. Operation: `coaDelete`."
                    },
                    "response": []
                },
                {
                    "name": "Update Account",
                    "request": {
                        "method": "PUT",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/coa/:id",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "coa",
                                ":id"
                            ],
                            "variable": [
                                {
                                    "key": "id",
                                    "value": "1",
                                    "description": "Account ID"
                                }
                            ]
                        },
                        "description": "Update an existing account in the chart of accounts. Only mutable\nfields (name, code, subtype, is_active) can be changed. Account type\ncannot be changed after creation.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `coaUpdate`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"name\": \"Office Supplies & Equipment\",\n    \"code\": \"6100\",\n    \"is_active\": true\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                }
            ]
        },
        {
            "name": "Contacts",
            "description": "Contact management for customers, vendors, and dual-role contacts.\nFull CRUD with entity scoping and type filtering.",
            "item": [
                {
                    "name": "List Contacts",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/contacts",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "contacts"
                            ],
                            "query": [
                                {
                                    "key": "type",
                                    "value": "customer",
                                    "description": "Filter by contact type",
                                    "disabled": true
                                },
                                {
                                    "key": "active",
                                    "value": "0",
                                    "description": "Filter by active status (defaults to active-only when omitted)",
                                    "disabled": true
                                }
                            ]
                        },
                        "description": "Retrieve contacts for the authenticated user's active entity.\nSupports optional filtering by contact type and active status.\nWhen `active` is omitted, only active contacts are returned.\n\nScope: `read`. Operation: `listContacts`."
                    },
                    "response": []
                },
                {
                    "name": "Create Contact",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/contacts",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "contacts"
                            ]
                        },
                        "description": "Create a new contact for the authenticated user's active entity.\nRequired fields are `display_name` (or `name`) and `type`.\nEmail uniqueness is enforced per entity.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `createContact`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"display_name\": \"Acme Corp\",\n    \"type\": \"customer\",\n    \"email\": \"billing@acme.com\",\n    \"phone\": \"555-0100\"\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Delete Contact",
                    "request": {
                        "method": "DELETE",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/contacts/:id",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "contacts",
                                ":id"
                            ],
                            "variable": [
                                {
                                    "key": "id",
                                    "value": "1",
                                    "description": "Contact ID"
                                }
                            ]
                        },
                        "description": "Permanently delete a contact by ID, scoped to the authenticated user's entity.\n\nScope: `write`. Roles: owner. Operation: `deleteContact`."
                    },
                    "response": []
                },
                {
                    "name": "Get Contact",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/contacts/:id",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "contacts",
                                ":id"
                            ],
                            "variable": [
                                {
                                    "key": "id",
                                    "value": "1",
                                    "description": "Contact ID"
                                }
                            ]
                        },
                        "description": "Retrieve a single contact by ID, scoped to the authenticated user's entity.\n\nScope: `read`. Operation: `getContact`."
                    },
                    "response": []
                },
                {
                    "name": "Update Contact",
                    "request": {
                        "method": "PUT",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/contacts/:id",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "contacts",
                                ":id"
                            ],
                            "variable": [
                                {
                                    "key": "id",
                                    "value": "1",
                                    "description": "Contact ID"
                                }
                            ]
                        },
                        "description": "Update an existing contact. Only provided fields are modified.\nAt least one updatable field must be included. Email uniqueness\nis enforced per entity (excluding the contact being updated).\nSending `null` for email or phone clears the value.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `updateContact`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"display_name\": \"Acme Corporation\",\n    \"phone\": \"555-0200\"\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                }
            ]
        },
        {
            "name": "Transactions",
            "description": "Double-entry journal entry management. Create balanced debit/credit\ntransactions, list with pagination, and manage dimension tags.",
            "item": [
                {
                    "name": "Record an expense",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/expenses",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "expenses"
                            ]
                        },
                        "description": "Creates a balanced journal entry: debits the expense account\n(`category_id`) and credits the payment account (`payment_account_id`).\nBrowser callers authenticate with the session cookie and must include\n`csrf_token`; bearer clients are exempt from CSRF.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `createExpense`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"amount\": 0,\n    \"description\": \"\",\n    \"expense_date\": \"2026-01-31\",\n    \"vendor_name\": \"\",\n    \"category_id\": 0,\n    \"payment_account_id\": 0,\n    \"reference\": \"\",\n    \"notes\": \"\",\n    \"entity_id\": 0,\n    \"csrf_token\": \"\"\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Create Journal Entry (enhanced)",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Idempotency-Key",
                                "value": "{{$guid}}",
                                "description": "Client-chosen unique key (1 to 255 characters). `X-Idempotency-Key` is accepted as an alias.",
                                "disabled": false
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/journal-entry",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "journal-entry"
                            ]
                        },
                        "description": "Create a balanced journal entry with the enhanced validation model.\n\nSend an `Idempotency-Key` header (`X-Idempotency-Key` works too; 1 to 255 characters) to make a retry safe: a repeat of the\nsame key by the same user within 24 hours returns the first response with `X-Idempotent-Replay: true` and writes nothing.\nWithout the header every call writes an entry. Owner or bookkeeper only; the date must not fall in a locked period.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `createJournalEntry`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"date\": \"2026-03-01\",\n    \"description\": \"Monthly rent payment\",\n    \"lines\": [\n        {\n            \"account_id\": 0\n        }\n    ]\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "List Transactions",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/transactions",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "transactions"
                            ],
                            "query": [
                                {
                                    "key": "page",
                                    "value": "1",
                                    "description": "Page number (1-based)",
                                    "disabled": true
                                },
                                {
                                    "key": "page_size",
                                    "value": "50",
                                    "description": "Number of records per page (max 100)",
                                    "disabled": true
                                },
                                {
                                    "key": "start_date",
                                    "value": "2024-01-01",
                                    "description": "Filter transactions from this date (inclusive, Y-m-d format)",
                                    "disabled": true
                                },
                                {
                                    "key": "end_date",
                                    "value": "2024-12-31",
                                    "description": "Filter transactions until this date (inclusive, Y-m-d format)",
                                    "disabled": true
                                },
                                {
                                    "key": "min_amount",
                                    "value": "",
                                    "description": "Filter transactions with amount >= this value",
                                    "disabled": true
                                },
                                {
                                    "key": "max_amount",
                                    "value": "",
                                    "description": "Filter transactions with amount <= this value",
                                    "disabled": true
                                },
                                {
                                    "key": "source",
                                    "value": "manual",
                                    "description": "Filter by transaction source",
                                    "disabled": true
                                },
                                {
                                    "key": "q",
                                    "value": "",
                                    "description": "Search in transaction description",
                                    "disabled": true
                                },
                                {
                                    "key": "entity_id",
                                    "value": "",
                                    "description": "Entity to list; defaults to the caller's active entity (POST /api/v1/entities/switch). An entity the caller is not a member of is answered 404.",
                                    "disabled": true
                                },
                                {
                                    "key": "per_page",
                                    "value": "50",
                                    "description": "Rows per page (alias of limit with page).",
                                    "disabled": true
                                },
                                {
                                    "key": "limit",
                                    "value": "50",
                                    "description": "Rows to return; wins over per_page.",
                                    "disabled": true
                                },
                                {
                                    "key": "offset",
                                    "value": "0",
                                    "description": "Rows to skip; wins over page.",
                                    "disabled": true
                                },
                                {
                                    "key": "status",
                                    "value": "manual",
                                    "description": "Only transactions with this source.",
                                    "disabled": true
                                }
                            ]
                        },
                        "description": "Retrieve a paginated list of transactions (journal entries) for one entity.\nSupports filtering by date range, amount range, source, and description search.\n\nScope: `read`. Operation: `listTransactions`."
                    },
                    "response": []
                },
                {
                    "name": "Create Journal Entry",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/transactions",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "transactions"
                            ]
                        },
                        "description": "Create a new journal entry (transaction) with debit and credit lines.\nThe entry must be balanced — total debits must equal total credits.\nEach line must be either a debit or a credit, not both.\nRequires at least 2 lines.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `createTransaction`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"date\": \"2024-01-15\",\n    \"description\": \"Office supplies purchase\",\n    \"entity_id\": 1,\n    \"lines\": [\n        {\n            \"account_id\": 1,\n            \"debit_amount\": \"100.00\",\n            \"credit_amount\": \"0.00\",\n            \"memo\": \"Office supplies\"\n        },\n        {\n            \"account_id\": 2,\n            \"debit_amount\": \"0.00\",\n            \"credit_amount\": \"100.00\",\n            \"memo\": \"Cash payment\"\n        }\n    ]\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Get Transaction Detail",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/transactions/:id",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "transactions",
                                ":id"
                            ],
                            "variable": [
                                {
                                    "key": "id",
                                    "value": "1",
                                    "description": "Transaction ID"
                                }
                            ]
                        },
                        "description": "Retrieve a single transaction by ID along with all its transaction lines.\nVerifies the authenticated user has access to the entity containing the transaction.\n\nScope: `read`. Operation: `getTransaction`."
                    },
                    "response": []
                },
                {
                    "name": "Get Transaction Dimension Tags",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/transactions/:id/dimension-tags",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "transactions",
                                ":id",
                                "dimension-tags"
                            ],
                            "variable": [
                                {
                                    "key": "id",
                                    "value": "1",
                                    "description": "Transaction ID"
                                }
                            ]
                        },
                        "description": "Retrieve dimension tags assigned to a specific transaction.\n\nScope: `read`. Operation: `getTransactionDimensionTags`."
                    },
                    "response": []
                },
                {
                    "name": "Update Transaction Dimension Tags",
                    "request": {
                        "method": "PUT",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/transactions/:id/dimension-tags",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "transactions",
                                ":id",
                                "dimension-tags"
                            ],
                            "variable": [
                                {
                                    "key": "id",
                                    "value": "1",
                                    "description": "Transaction ID"
                                }
                            ]
                        },
                        "description": "Replace all dimension tags on a transaction with the provided set.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `updateTransactionDimensionTags`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"dimension_value_ids\": [\n        3,\n        7\n    ]\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                }
            ]
        },
        {
            "name": "Invoices",
            "description": "Invoice lifecycle management — create drafts, send to customers, record\npayments, match to bank deposits, and send overdue reminders.",
            "item": [
                {
                    "name": "List Invoices",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/invoices",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "invoices"
                            ],
                            "query": [
                                {
                                    "key": "page",
                                    "value": "1",
                                    "description": "Page number (1-based)",
                                    "disabled": true
                                },
                                {
                                    "key": "per_page",
                                    "value": "50",
                                    "description": "Results per page (max 100)",
                                    "disabled": true
                                },
                                {
                                    "key": "status",
                                    "value": "draft",
                                    "description": "Filter by invoice status",
                                    "disabled": true
                                },
                                {
                                    "key": "contact_id",
                                    "value": "",
                                    "description": "Filter by contact/customer ID",
                                    "disabled": true
                                },
                                {
                                    "key": "start_date",
                                    "value": "",
                                    "description": "Filter invoices on or after this date (YYYY-MM-DD)",
                                    "disabled": true
                                },
                                {
                                    "key": "end_date",
                                    "value": "",
                                    "description": "Filter invoices on or before this date (YYYY-MM-DD)",
                                    "disabled": true
                                }
                            ]
                        },
                        "description": "Retrieve invoices for the authenticated user's active entity.\nSupports pagination and optional filtering by status, contact, and date range.\n\nScope: `read`. Operation: `listInvoices`."
                    },
                    "response": []
                },
                {
                    "name": "Create an invoice",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/invoices",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "invoices"
                            ]
                        },
                        "description": "RESTful alias of `/api/v1/invoices/create` -- same handler, same required\nwrite scope and owner/bookkeeper role. Registered because the Flutter\nclient posts to this path.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `createInvoiceRest`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"contact_id\": 10,\n    \"invoice_date\": \"2026-01-15\",\n    \"due_date\": \"2026-02-15\",\n    \"subtotal\": \"1000.00\",\n    \"total\": \"1000.00\",\n    \"invoice_number\": \"INV-001\",\n    \"notes\": \"Net 30\",\n    \"lines\": [\n        {\n            \"description\": \"Consulting\",\n            \"quantity\": 10,\n            \"unit_price\": 100\n        }\n    ]\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Create Invoice",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/invoices/create",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "invoices",
                                "create"
                            ]
                        },
                        "description": "Create an invoice in `draft` status for the caller's active entity. The entity is never taken from the body.\n\nSend `contact_id` (a customer of this business), `invoice_date` and `lines` (each with `description`, `quantity`,\n`unit_price`); `due_date`, `invoice_number` and `notes` are optional. The stored `subtotal` and `total` are computed from\nthe lines, whatever the request says. `invoice_number` (at most 100 characters) is unique per business: a second invoice\nwith the same number is 409 `DUPLICATE_INVOICE_NUMBER`, which makes it a safe key for retrying a create.\n\nEmits `invoice.created`. Next: `POST /api/v1/invoices/{id}/send` (optional), `POST /api/v1/invoices/{id}/finalize`, then\n`POST /api/v1/invoices/record-payment`.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `createInvoice`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"contact_id\": 10,\n    \"invoice_date\": \"2024-01-15\",\n    \"due_date\": \"2024-02-15\",\n    \"subtotal\": \"1000.00\",\n    \"total\": \"1000.00\",\n    \"invoice_number\": \"INV-001\",\n    \"notes\": \"Net 30\",\n    \"lines\": [\n        {\n            \"description\": \"Consulting\",\n            \"quantity\": 10,\n            \"unit_price\": 100\n        }\n    ]\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Mark Invoice as Paid",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/invoices/paid/:invoiceId",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "invoices",
                                "paid",
                                ":invoiceId"
                            ],
                            "variable": [
                                {
                                    "key": "invoiceId",
                                    "value": "1",
                                    "description": "Invoice ID"
                                }
                            ]
                        },
                        "description": "Mark an invoice as paid. The invoice must NOT be in \"draft\" or \"void\" status,\nand must have zero outstanding balance (all payments recorded via recordPayment).\nThis endpoint does not accept payment details (payment_date, payment_method,\npayment_reference) — use the recordPayment endpoint for that.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `markInvoicePaid`."
                    },
                    "response": []
                },
                {
                    "name": "Match Payment to Bank Deposit",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/invoices/payments/match-deposit",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "invoices",
                                "payments",
                                "match-deposit"
                            ]
                        },
                        "description": "Link an invoice payment to a bank deposit transaction for reconciliation.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `matchPaymentToDeposit`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"invoice_payment_id\": 12,\n    \"bank_transaction_id\": 345\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Record Invoice Payment",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/invoices/record-payment",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "invoices",
                                "record-payment"
                            ]
                        },
                        "description": "Record a payment against a finalized or partial invoice: posts Dr deposit account / Cr Accounts Receivable, writes the\npayment row and moves the invoice to `partial` or, when the balance reaches zero, `paid` (which emits `invoice.paid`).\nThe invoice must be finalized first (`POST /api/v1/invoices/{id}/finalize`); a draft or sent invoice is refused.\n\n`amount` may be a number or a string such as `\"1,500.00\"`; `payment_date` must be a real `YYYY-MM-DD` date outside any closed\naccounts-receivable period (409 `PERIOD_LOCKED`); `deposit_account_id` is an account of this business. `payment_method`\n(50 characters), `reference_number` (255) and `notes` (500) are optional.\n\nAccepts a bearer token or API key with the `write` scope; the web invoice page posts the same route with its session and\n`csrf_token`. Owner or bookkeeper only.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `recordInvoicePayment`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"invoice_id\": 0,\n    \"amount\": 0,\n    \"payment_date\": \"2026-01-31\",\n    \"deposit_account_id\": 0,\n    \"payment_method\": \"\",\n    \"reference_number\": \"\",\n    \"notes\": \"\",\n    \"csrf_token\": \"\"\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Send Invoice",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/invoices/send/:invoiceId",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "invoices",
                                "send",
                                ":invoiceId"
                            ],
                            "variable": [
                                {
                                    "key": "invoiceId",
                                    "value": "1",
                                    "description": "Invoice ID"
                                }
                            ]
                        },
                        "description": "Send an invoice to the customer via email with a generated PDF attachment.\nThe invoice must be in \"draft\" status. On success, the status transitions to \"sent\".\nThe sequence is strict: PDF generation and email delivery must both succeed\nbefore the status is updated.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `sendInvoice`."
                    },
                    "response": []
                },
                {
                    "name": "Finalize Invoice",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/invoices/:id/finalize",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "invoices",
                                ":id",
                                "finalize"
                            ],
                            "variable": [
                                {
                                    "key": "id",
                                    "value": "1",
                                    "description": "Invoice ID"
                                }
                            ]
                        },
                        "description": "Post a draft or sent invoice to the ledger (debit Accounts Receivable, credit Revenue for the invoice\ntotal) and open it for payment. This is the step between sending an invoice and recording a payment\nagainst it: `POST /api/v1/invoices/record-payment` only accepts a `finalized` or `partial` invoice.\n\nThe invoice must be `draft` or `sent`; its date must not fall in a closed accounts-receivable period\n(409 `PERIOD_LOCKED`); the business needs an active receivable asset account and an active income\naccount (422 `NO_AR_ACCOUNT`, `NO_REVENUE_ACCOUNT`); and the total must be greater than zero. The status\nchange is the claim, taken inside the posting transaction, so two simultaneous calls post once and the\nother gets 409. Call it again after success and the answer is 409 `INVOICE_NOT_FINALIZABLE`.\n\nRequires the `write` scope and the `owner` or `bookkeeper` role.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `finalizeInvoice`."
                    },
                    "response": []
                },
                {
                    "name": "Send Overdue Payment Reminder",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/invoices/:id/send-reminder",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "invoices",
                                ":id",
                                "send-reminder"
                            ],
                            "variable": [
                                {
                                    "key": "id",
                                    "value": "1",
                                    "description": "Invoice ID"
                                }
                            ]
                        },
                        "description": "Send a payment reminder email for an overdue invoice. The amount shown is the\nbalance due, the entity's Reply-to address is used, and the send is logged so\nthe daily reminder run counts its cadence from it. Owner or bookkeeper only.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `sendInvoiceReminder`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"recipient_email\": \"user@example.com\"\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Get an invoice",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/invoices/:invoiceId",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "invoices",
                                ":invoiceId"
                            ],
                            "variable": [
                                {
                                    "key": "invoiceId",
                                    "value": "1",
                                    "description": ""
                                }
                            ]
                        },
                        "description": "Single invoice, scoped to the caller's entity. Requested by the Flutter invoice detail screen.\n\nScope: `read`. Operation: `getInvoice`."
                    },
                    "response": []
                },
                {
                    "name": "Send an invoice",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/invoices/:invoiceId/send",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "invoices",
                                ":invoiceId",
                                "send"
                            ],
                            "variable": [
                                {
                                    "key": "invoiceId",
                                    "value": "1",
                                    "description": ""
                                }
                            ]
                        },
                        "description": "RESTful alias of `/api/v1/invoices/send/{invoiceId}` -- same handler, write scope and owner/bookkeeper role.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `sendInvoiceRest`."
                    },
                    "response": []
                }
            ]
        },
        {
            "name": "Dimensions",
            "description": "Dimension types and values for transaction tagging and multi-dimensional\nreporting. Supports department, location, project, and custom dimensions.",
            "item": [
                {
                    "name": "List all dimensions",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/dimensions",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "dimensions"
                            ],
                            "query": [
                                {
                                    "key": "type",
                                    "value": "",
                                    "description": "Only values of this dimension type (by name).",
                                    "disabled": true
                                },
                                {
                                    "key": "q",
                                    "value": "",
                                    "description": "Free text matched against names.",
                                    "disabled": true
                                },
                                {
                                    "key": "active_only",
                                    "value": "true",
                                    "description": "false includes deactivated dimensions.",
                                    "disabled": true
                                },
                                {
                                    "key": "limit",
                                    "value": "50",
                                    "description": "Rows per page; above 200 is clamped to 200.",
                                    "disabled": true
                                },
                                {
                                    "key": "offset",
                                    "value": "0",
                                    "description": "Rows to skip.",
                                    "disabled": true
                                }
                            ]
                        },
                        "description": "Retrieve all dimension types and their values for the authenticated entity.\nReturns a flat list of dimension records (types and values).\n\nScope: `read`. Operation: `listDimensions`."
                    },
                    "response": []
                },
                {
                    "name": "Create a dimension",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/dimensions",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "dimensions"
                            ]
                        },
                        "description": "Create a new dimension type or value.\nRequires `name` and `value` fields in the JSON body.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `createDimension`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"name\": \"Department\",\n    \"value\": \"Marketing\"\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Delete a dimension",
                    "request": {
                        "method": "DELETE",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/dimensions/:id",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "dimensions",
                                ":id"
                            ],
                            "variable": [
                                {
                                    "key": "id",
                                    "value": "1",
                                    "description": "Dimension ID to delete"
                                }
                            ]
                        },
                        "description": "Delete a dimension type or value by ID.\n\nScope: `delete`. Roles: owner, bookkeeper. Operation: `deleteDimension`."
                    },
                    "response": []
                },
                {
                    "name": "Update a dimension",
                    "request": {
                        "method": "PUT",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/dimensions/:id",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "dimensions",
                                ":id"
                            ],
                            "variable": [
                                {
                                    "key": "id",
                                    "value": "1",
                                    "description": "Dimension ID to update"
                                }
                            ]
                        },
                        "description": "Update an existing dimension type or value by ID.\nAt least one of `name` or `value` must be provided.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `updateDimension`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"name\": \"Department\",\n    \"value\": \"Marketing (Renamed)\"\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                }
            ]
        },
        {
            "name": "Bills",
            "description": "Bill management (accounts payable) — create, list, pay bills, and retrieve\nform defaults. Bill payments generate GL journal entries automatically.",
            "item": [
                {
                    "name": "List Bills",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/bills",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "bills"
                            ],
                            "query": [
                                {
                                    "key": "page",
                                    "value": "1",
                                    "description": "Page number, from 1.",
                                    "disabled": true
                                },
                                {
                                    "key": "per_page",
                                    "value": "20",
                                    "description": "Rows per page; above 100 is clamped to 100.",
                                    "disabled": true
                                },
                                {
                                    "key": "status",
                                    "value": "paid",
                                    "description": "Paid state. Any other value is ignored. The workflow state (draft, approved, paid) is in each bill's `status`.",
                                    "disabled": true
                                },
                                {
                                    "key": "search",
                                    "value": "",
                                    "description": "Free text matched against vendor name and description.",
                                    "disabled": true
                                },
                                {
                                    "key": "overdue",
                                    "value": "",
                                    "description": "true: only unpaid bills past their due date.",
                                    "disabled": true
                                }
                            ]
                        },
                        "description": "Returns all bills for the authenticated user's entity, ordered by due_date ascending.\nNo pagination — returns the complete list with a count.\n\nScope: `read`. Operation: `listBills`."
                    },
                    "response": []
                },
                {
                    "name": "Create Bill",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/bills",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "bills"
                            ]
                        },
                        "description": "Create a new bill (accounts payable) for the authenticated user's entity.\nThe bill is created as a draft against a vendor contact, found by exact\nname or created from vendor_name. Nothing posts to the ledger until the\nbill is approved, so paid=true is refused with 422.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `createBill`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"amount\": \"500.00\",\n    \"due_date\": \"2024-02-15\",\n    \"vendor_name\": \"Office Supply Co\",\n    \"description\": \"Monthly supplies\"\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Get Bill Creation Defaults",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/bills/create-defaults",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "bills",
                                "create-defaults"
                            ]
                        },
                        "description": "Retrieve default values for the bill creation form including\ndefault date, due date, payment status, and allowed statuses.\n\nScope: `read`. Operation: `getBillCreateDefaults`."
                    },
                    "response": []
                },
                {
                    "name": "Match Bill Payment to Bank Withdrawal",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/bills/payments/match-withdrawal",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "bills",
                                "payments",
                                "match-withdrawal"
                            ]
                        },
                        "description": "Link a bill payment to a bank withdrawal transaction for reconciliation,\nand mark the bank transaction posted to that payment's journal so it cannot\nbe posted to the ledger a second time. The payment is the one already\nlinked to this bank transaction, else bill_payment_id, else the bill's only\nunmatched payment. Conflict-safe: refuses to overwrite an existing link on\nthe bill payment or on the bank transaction.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `matchBillPaymentToBankWithdrawal`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"bill_id\": 42,\n    \"bank_transaction_id\": 789\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Get Bill",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/bills/:id",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "bills",
                                ":id"
                            ],
                            "variable": [
                                {
                                    "key": "id",
                                    "value": "1",
                                    "description": "Bill ID"
                                }
                            ]
                        },
                        "description": "Get a single bill by ID. Scoped to the authenticated entity — returns 404\nfor bills that belong to another entity.\n\nScope: `read`. Operation: `getBill`."
                    },
                    "response": []
                },
                {
                    "name": "Update Bill",
                    "request": {
                        "method": "PUT",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/bills/:id",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "bills",
                                ":id"
                            ],
                            "variable": [
                                {
                                    "key": "id",
                                    "value": "1",
                                    "description": "Bill ID"
                                }
                            ]
                        },
                        "description": "Update fields of a draft bill. Allowed fields: vendor_name, description,\namount, due_date, bill_date. Only drafts are editable: an approved bill has\nalready posted its accrual, so any other status returns 409. amount is also\nrefused with 409 on a bill that has line items (it is their sum). Returns\nthe updated bill object.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `updateBill`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"vendor_name\": \"Office Supply Co\",\n    \"description\": \"Updated monthly supplies order\",\n    \"amount\": 550,\n    \"due_date\": \"2024-02-28\"\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Approve Bill",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/bills/:id/approve",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "bills",
                                ":id",
                                "approve"
                            ],
                            "variable": [
                                {
                                    "key": "id",
                                    "value": "1",
                                    "description": "Bill ID"
                                }
                            ]
                        },
                        "description": "Post a draft bill to the ledger (debit the expense account, credit Accounts Payable for the bill total)\nand make it payable. A bill is created as a draft, and `POST /api/v1/bills/{id}/pay` only accepts an\n`approved` bill, so this is the step in between.\n\nA bill created over the API has no line items, so the request names the expense account its amount is\ncharged to (`expense_account_id`, an active expense account of this business); a bill that already has\nlines needs no body. The bill must be `draft`, its date must not fall in a closed accounts-payable period\n(409 `PERIOD_LOCKED`), the business needs an active payable liability account (422 `NO_AP_ACCOUNT`) and the\ntotal must be greater than zero. The status change is the claim, taken inside the posting transaction, so\ntwo simultaneous calls post once.\n\nRequires the `write` scope and the `owner` or `bookkeeper` role.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `approveBill`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"expense_account_id\": 52\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Pay Bill",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/bills/:id/pay",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "bills",
                                ":id",
                                "pay"
                            ],
                            "variable": [
                                {
                                    "key": "id",
                                    "value": "1",
                                    "description": "Bill ID"
                                }
                            ]
                        },
                        "description": "Pay an approved bill: posts the journal entry (debit Accounts Payable, credit the business's cash or bank account for\nthe bill total, dated today), records the bill payment and marks the bill `paid`. A draft cannot be paid: create it, then\n`POST /api/v1/bills/{id}/approve`, then pay it.\n\nPaying a bill that is already paid is not an error: the answer is 200 with `already_paid: true` and the current bill.\nThe payment date must not fall in a closed accounts-payable period (409 `BUSINESS_RULE_ERROR`). Emits `bill.paid`.\n\nRequires the `write` scope and the `owner` or `bookkeeper` role.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `payBill`."
                    },
                    "response": []
                }
            ]
        },
        {
            "name": "Reports",
            "description": "Financial reports including Profit & Loss, Cash Flow, AR/AP Aging,\nExpense by Category, Sales by Customer, and AI-powered narratives.",
            "item": [
                {
                    "name": "Get Filtered Reports",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/reports?entity_id=",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "reports"
                            ],
                            "query": [
                                {
                                    "key": "entity_id",
                                    "value": "",
                                    "description": "(Required) Entity ID for multi-tenant isolation",
                                    "disabled": false
                                },
                                {
                                    "key": "start_date",
                                    "value": "2024-01-01",
                                    "description": "Report period start date (YYYY-MM-DD)",
                                    "disabled": true
                                },
                                {
                                    "key": "end_date",
                                    "value": "2024-12-31",
                                    "description": "Report period end date (YYYY-MM-DD)",
                                    "disabled": true
                                },
                                {
                                    "key": "report_type",
                                    "value": "trial_balance",
                                    "description": "Type of financial report to generate",
                                    "disabled": true
                                },
                                {
                                    "key": "category",
                                    "value": "",
                                    "description": "Filter by category (max 100 chars)",
                                    "disabled": true
                                },
                                {
                                    "key": "account_type",
                                    "value": "asset",
                                    "description": "Filter by account type",
                                    "disabled": true
                                },
                                {
                                    "key": "account_code",
                                    "value": "",
                                    "description": "Filter by account code (partial match, max 50 chars)",
                                    "disabled": true
                                },
                                {
                                    "key": "page",
                                    "value": "1",
                                    "description": "Page number for pagination",
                                    "disabled": true
                                },
                                {
                                    "key": "per_page",
                                    "value": "50",
                                    "description": "Items per page (max 100)",
                                    "disabled": true
                                }
                            ]
                        },
                        "description": "Retrieve financial reports with filtering and pagination. Supports\ntrial balance, profit & loss, balance sheet, cash flow, and general ledger\nreport types via the `report_type` parameter.\n\nScope: `read`. Operation: `getFilteredReports`."
                    },
                    "response": []
                },
                {
                    "name": "Accounts Payable Aging Report",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/reports/ap-aging?entity_id=",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "reports",
                                "ap-aging"
                            ],
                            "query": [
                                {
                                    "key": "entity_id",
                                    "value": "",
                                    "description": "(Required) Entity ID to generate report for. Must match an entity the authenticated user has access to.",
                                    "disabled": false
                                },
                                {
                                    "key": "as_of_date",
                                    "value": "2024-12-31",
                                    "description": "Report as-of date (YYYY-MM-DD). Defaults to today.",
                                    "disabled": true
                                }
                            ]
                        },
                        "description": "Generate an Accounts Payable (AP) aging report grouped by age bucket.\nBuckets: current, 1-30 days, 31-60 days, 61-90 days, 91+ days.\nOnly includes unpaid bills (paid=0).\nUses direct-auth pattern (bearer token validated in controller).\n\nScope: `read`. Operation: `getApAgingReport`."
                    },
                    "response": []
                },
                {
                    "name": "Accounts Receivable Aging Report",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/reports/ar-aging",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "reports",
                                "ar-aging"
                            ],
                            "query": [
                                {
                                    "key": "entity_id",
                                    "value": "",
                                    "description": "Entity ID to generate report for. Must match an entity the authenticated user has access to. If omitted, defaults to the user's first available entity.",
                                    "disabled": true
                                },
                                {
                                    "key": "as_of_date",
                                    "value": "2024-12-31",
                                    "description": "Report as-of date (YYYY-MM-DD). Defaults to today.",
                                    "disabled": true
                                }
                            ]
                        },
                        "description": "Generate an Accounts Receivable (AR) aging report grouped by age bucket.\nBuckets: current, 1-30 days, 31-60 days, 61-90 days, 91+ days.\nUses direct-auth pattern (bearer token validated in controller).\n\nScope: `read`. Operation: `getArAgingReport`."
                    },
                    "response": []
                },
                {
                    "name": "Balance sheet",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/reports/bs",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "reports",
                                "bs"
                            ],
                            "query": [
                                {
                                    "key": "entity_id",
                                    "value": "",
                                    "description": "",
                                    "disabled": true
                                },
                                {
                                    "key": "as_of_date",
                                    "value": "",
                                    "description": "",
                                    "disabled": true
                                },
                                {
                                    "key": "end_date",
                                    "value": "",
                                    "description": "Balance sheet as of this date (alias of as_of_date).",
                                    "disabled": true
                                }
                            ]
                        },
                        "description": "Balance sheet for the caller's entity. Equivalent to\n`/api/v1/reports?report_type=balance_sheet`, exposed under its own path\nbecause that is what the Flutter reports screen requests. The entity is\nresolved from membership when `entity_id` is omitted.\n\nScope: `read`. Operation: `getBalanceSheet`."
                    },
                    "response": []
                },
                {
                    "name": "Generate Cash Flow Report",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/reports/cashflow",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "reports",
                                "cashflow"
                            ],
                            "query": [
                                {
                                    "key": "entity_id",
                                    "value": "",
                                    "description": "Entity to report on. Defaults to the caller's active entity; an entity the caller is not a member of returns 404.",
                                    "disabled": true
                                },
                                {
                                    "key": "start_date",
                                    "value": "2024-01-01",
                                    "description": "Report period start date (YYYY-MM-DD)",
                                    "disabled": true
                                },
                                {
                                    "key": "end_date",
                                    "value": "2024-12-31",
                                    "description": "Report period end date (YYYY-MM-DD)",
                                    "disabled": true
                                },
                                {
                                    "key": "transaction_type",
                                    "value": "income",
                                    "description": "Filter by the transaction's source",
                                    "disabled": true
                                }
                            ]
                        },
                        "description": "Cash movement per transaction over a date range. A transaction's\nnet_amount is the change in bank and cash accounts it caused, so a\nbalanced entry that never touches cash (an invoice, say) reports 0.00,\nand a transfer between two bank accounts nets to zero.\n\nScope: `read`. Operation: `cashFlowReport`."
                    },
                    "response": []
                },
                {
                    "name": "Expense by category report",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/reports/expense-by-category",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "reports",
                                "expense-by-category"
                            ],
                            "query": [
                                {
                                    "key": "entity_id",
                                    "value": "",
                                    "description": "Entity ID (must match an entity the user has membership to)",
                                    "disabled": true
                                },
                                {
                                    "key": "start_date",
                                    "value": "2026-01-01",
                                    "description": "Start date in Y-m-d format (defaults to first day of current month)",
                                    "disabled": true
                                },
                                {
                                    "key": "end_date",
                                    "value": "2026-01-31",
                                    "description": "End date in Y-m-d format (defaults to today)",
                                    "disabled": true
                                }
                            ]
                        },
                        "description": "Returns expense amounts aggregated by account (category) within a date range.\nFlutter-friendly response includes `percent_of_total` per category and parallel\n`chart.labels[]` / `chart.values[]` arrays for direct widget binding.\n\nEntity is resolved from the authenticated user's memberships. An optional\n`entity_id` query param can switch entity but must match a valid membership.\n\nScope: `read`. Operation: `getExpenseByCategory`."
                    },
                    "response": []
                },
                {
                    "name": "Report Trend/Delta Analysis",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/reports/explainability",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "reports",
                                "explainability"
                            ]
                        },
                        "description": "Compare two sets of already-computed metrics and return the v2\nexplainability payload — trends, deltas and suggestions derived from\nthem.\n\nThis endpoint does NOT fetch a report. It used to be documented as\ntaking `report_type` with a date range, and the handler has never read\nany of those fields: it requires `current_metrics` and\n`previous_metrics` and 422s without them, so the documented body could\nnot succeed. The caller computes the two periods and sends the numbers.\n\nScope: `read`. Operation: `analyzeReportExplainability`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"current_metrics\": {\n        \"revenue\": 125000,\n        \"cogs\": 48000,\n        \"opex\": 39000\n    },\n    \"previous_metrics\": {\n        \"revenue\": 110000,\n        \"cogs\": 45000,\n        \"opex\": 41000\n    },\n    \"context\": {\n        \"period_label\": \"Q3 2026\"\n    }\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Generate Report Narrative",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/reports/narrative",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "reports",
                                "narrative"
                            ]
                        },
                        "description": "Generate an AI-powered plain-English narrative for a financial report.\n\nScope: `read`. Operation: `generateReportNarrative`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"report_type\": \"profit_loss\",\n    \"start_date\": \"2026-01-01\",\n    \"end_date\": \"2026-03-31\"\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Generate Profit & Loss Report",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/reports/pl?entity_id=",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "reports",
                                "pl"
                            ],
                            "query": [
                                {
                                    "key": "entity_id",
                                    "value": "",
                                    "description": "(Required) Entity ID for multi-tenant isolation",
                                    "disabled": false
                                },
                                {
                                    "key": "start_date",
                                    "value": "2024-01-01",
                                    "description": "Report period start date (YYYY-MM-DD)",
                                    "disabled": true
                                },
                                {
                                    "key": "end_date",
                                    "value": "2024-12-31",
                                    "description": "Report period end date (YYYY-MM-DD)",
                                    "disabled": true
                                },
                                {
                                    "key": "account_type",
                                    "value": "income",
                                    "description": "Filter by account type",
                                    "disabled": true
                                },
                                {
                                    "key": "account_code",
                                    "value": "",
                                    "description": "Filter by account code (partial match, max 50 chars)",
                                    "disabled": true
                                },
                                {
                                    "key": "department",
                                    "value": "",
                                    "description": "Filter by department (max 100 chars)",
                                    "disabled": true
                                },
                                {
                                    "key": "tag",
                                    "value": "",
                                    "description": "Filter by tag (max 50 chars)",
                                    "disabled": true
                                },
                                {
                                    "key": "dimensions",
                                    "value": "category,class",
                                    "description": "Comma-separated list of dimensions to group by",
                                    "disabled": true
                                },
                                {
                                    "key": "compare_to_previous",
                                    "value": "true",
                                    "description": "Include comparison to the previous period",
                                    "disabled": true
                                }
                            ]
                        },
                        "description": "Generate a Profit & Loss (P&L / Income Statement) report for a given entity.\nSupports date range filtering, dimension grouping, and comparison to the previous period.\n\nScope: `read`. Operation: `generatePLReport`."
                    },
                    "response": []
                },
                {
                    "name": "Sales by customer report",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/reports/sales-by-customer",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "reports",
                                "sales-by-customer"
                            ],
                            "query": [
                                {
                                    "key": "start_date",
                                    "value": "2026-01-01",
                                    "description": "Start date in Y-m-d format (defaults to first day of current month)",
                                    "disabled": true
                                },
                                {
                                    "key": "end_date",
                                    "value": "2026-01-31",
                                    "description": "End date in Y-m-d format (defaults to today)",
                                    "disabled": true
                                }
                            ]
                        },
                        "description": "Returns invoice income aggregated by contact (customer) within a date range.\nExcludes draft, void, and deleted invoices. Contacts with no valid `contact_id`\nare grouped under an \"Unassigned Contact\" fallback label.\n\nEntity is resolved from the authenticated user's memberships.\n\nScope: `read`. Operation: `getSalesByCustomer`."
                    },
                    "response": []
                },
                {
                    "name": "Quarterly Tax Estimate",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/tax/estimate",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "tax",
                                "estimate"
                            ],
                            "query": [
                                {
                                    "key": "quarter",
                                    "value": "",
                                    "description": "Tax quarter (1-4)",
                                    "disabled": true
                                },
                                {
                                    "key": "year",
                                    "value": "",
                                    "description": "Tax year",
                                    "disabled": true
                                },
                                {
                                    "key": "net_income_ytd",
                                    "value": "",
                                    "description": "Override the year-to-date net income read from the books.",
                                    "disabled": true
                                },
                                {
                                    "key": "tax_paid_ytd",
                                    "value": "",
                                    "description": "Tax already paid this year.",
                                    "disabled": true
                                },
                                {
                                    "key": "effective_tax_rate",
                                    "value": "",
                                    "description": "Override the effective rate.",
                                    "disabled": true
                                }
                            ]
                        },
                        "description": "Get quarterly estimated tax payment calculation based on P&L snapshot.\n\nScope: `read`. Operation: `getTaxEstimate`."
                    },
                    "response": []
                }
            ]
        },
        {
            "name": "API Keys",
            "description": "API key lifecycle management — create, list, update, rotate, and revoke\nkeys with scope-based permissions (read, write, admin, delete).",
            "item": [
                {
                    "name": "API Key Usage Metrics",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/api-keys/:keyId/metrics",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "api-keys",
                                ":keyId",
                                "metrics"
                            ],
                            "query": [
                                {
                                    "key": "from",
                                    "value": "",
                                    "description": "First day, YYYY-MM-DD.",
                                    "disabled": true
                                },
                                {
                                    "key": "to",
                                    "value": "",
                                    "description": "Last day, YYYY-MM-DD.",
                                    "disabled": true
                                }
                            ],
                            "variable": [
                                {
                                    "key": "keyId",
                                    "value": "1",
                                    "description": "API key ID"
                                }
                            ]
                        },
                        "description": "Get usage metrics and statistics for a specific API key.\n\nScope: `read`. Operation: `getApiKeyMetrics`."
                    },
                    "response": []
                },
                {
                    "name": "List API keys",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/keys",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "keys"
                            ],
                            "query": [
                                {
                                    "key": "active",
                                    "value": "true",
                                    "description": "Filter to only active (non-expired) keys",
                                    "disabled": true
                                },
                                {
                                    "key": "expired",
                                    "value": "true",
                                    "description": "Filter to only expired keys",
                                    "disabled": true
                                }
                            ]
                        },
                        "description": "Returns all API keys belonging to the authenticated user.\nKeys are returned in reverse chronological order (newest first).\nThe actual key secret is never included — only metadata and a masked prefix.\n\nScope: `read`. Operation: `listApiKeys`."
                    },
                    "response": []
                },
                {
                    "name": "Create a new API key",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/keys",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "keys"
                            ]
                        },
                        "description": "Creates a new API key with the specified name and scopes.\nThe plaintext key is returned **only once** in this response and cannot be\nretrieved again. Store it securely immediately after creation.\n\nScope: `admin`. Operation: `createApiKey`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"name\": \"Production Key\",\n    \"scopes\": [\n        \"read\",\n        \"write\"\n    ],\n    \"expires_at\": \"2026-12-31\"\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Revoke an API key",
                    "request": {
                        "method": "DELETE",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/keys/:id",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "keys",
                                ":id"
                            ],
                            "variable": [
                                {
                                    "key": "id",
                                    "value": "1",
                                    "description": "The API key ID to revoke"
                                }
                            ]
                        },
                        "description": "Permanently revokes an API key. The key will no longer be usable\nfor authentication. This action cannot be undone.\n\nScope: `admin`. Operation: `deleteApiKey`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"reason\": \"Key compromised\"\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Update an API key",
                    "request": {
                        "method": "PUT",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/keys/:id",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "keys",
                                ":id"
                            ],
                            "variable": [
                                {
                                    "key": "id",
                                    "value": "1",
                                    "description": "The API key ID"
                                }
                            ]
                        },
                        "description": "Updates the name, scopes, or expiration of an existing API key.\nAll fields are optional — only provided fields are changed.\nSet `expires_at` to `null` to remove the expiration.\n\nScope: `admin`. Operation: `updateApiKey`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"name\": \"Renamed Key\",\n    \"scopes\": [\n        \"read\",\n        \"write\",\n        \"admin\"\n    ],\n    \"expires_at\": \"2027-12-31\"\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Usage summary for the caller's API keys",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/usage/keys",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "usage",
                                "keys"
                            ],
                            "query": [
                                {
                                    "key": "range",
                                    "value": "30d",
                                    "description": "",
                                    "disabled": true
                                }
                            ]
                        },
                        "description": "Per-key request, success and error counts over the selected range.\nNever returns key material. Read-only, so no CSRF token is needed;\naccepts a bearer token or the session identity.\n\nScope: `read`. Operation: `getApiKeyUsageSummary`."
                    },
                    "response": []
                }
            ]
        },
        {
            "name": "Dashboard",
            "description": "Composite dashboard summary for mobile clients with health metrics,\ncompleteness indicators, and next-action recommendations.",
            "item": [
                {
                    "name": "Get dashboard summary",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/dashboard",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "dashboard"
                            ]
                        },
                        "description": "Returns a composite dashboard payload for the authenticated user\ncontaining health status, profile completeness, and next recommended action.\nDesigned for the Flutter mobile client home screen.\n\nScope: `read`. Operation: `getDashboardSummary`."
                    },
                    "response": []
                }
            ]
        },
        {
            "name": "Approvals",
            "description": "Approval review queue — list pending items, approve or edit them.\nUsed for human review of AI-suggested transactions.",
            "item": [
                {
                    "name": "Approve a pending request",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/approvals/approve",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "approvals",
                                "approve"
                            ]
                        },
                        "description": "Marks a pending approval request as approved. Only items with\nstatus \"pending\" can be approved. Returns the updated approval record.\nA 409 Conflict is returned if the item was already processed by another reviewer.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `approveApprovalRequest`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"approval_id\": 1,\n    \"review_notes\": \"Amounts verified against bank statement\"\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Edit a pending approval request",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/approvals/edit",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "approvals",
                                "edit"
                            ]
                        },
                        "description": "Updates editable fields on a pending approval request. Only items with\nstatus \"pending\" can be edited — once reviewed, the record is frozen.\nAt least one editable field must be provided.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `editApprovalRequest`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"approval_id\": 1,\n    \"title\": \"Updated review title\",\n    \"priority\": 4\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "List approval queue",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/approvals/queue",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "approvals",
                                "queue"
                            ],
                            "query": [
                                {
                                    "key": "status",
                                    "value": "pending",
                                    "description": "Filter by approval status",
                                    "disabled": true
                                },
                                {
                                    "key": "limit",
                                    "value": "20",
                                    "description": "Maximum number of items to return (1-100)",
                                    "disabled": true
                                },
                                {
                                    "key": "offset",
                                    "value": "0",
                                    "description": "Number of items to skip for pagination",
                                    "disabled": true
                                }
                            ]
                        },
                        "description": "Returns a paginated list of approval requests filtered by status.\nDefaults to pending items. Only accessible by authenticated users.\n\nScope: `read`. Roles: owner, bookkeeper, accountant. Operation: `listApprovalQueue`."
                    },
                    "response": []
                }
            ]
        },
        {
            "name": "Receipts",
            "description": "Receipt processing pipeline — upload images (multipart), extract data\nvia OCR (OpenAI Vision), confirm/correct extracted fields, and submit\nfeedback for learning. Supports both URL and base64 image inputs.",
            "item": [
                {
                    "name": "Receipts by Email (Mailgun inbound)",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/receipts/inbound/json",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "receipts",
                                "inbound",
                                "json"
                            ]
                        },
                        "description": "Receives a receipt emailed to a business's private receipts address\n(receipts+<token>@ the inbound domain), forwarded by a Mailgun route. Mailgun\nposts the parsed message as JSON because the URL ends in \"json\", signed with\nthe account's HTTP webhook signing key: X-Mailgun-Signature is the hex\nHMAC-SHA256 of X-Mailgun-Timestamp followed by the raw body. A form post\n(timestamp, token, signature fields; token single-use) is accepted too.\nNot bearer-authenticated: the signature is the credential, and an unverifiable\nrequest is refused with 401 before anything is stored. The business is the\ninbox whose token is in the recipient address. Each attachment (JPEG, PNG,\nWebP, HEIC or PDF, up to 10) becomes a receipt in the review queue; a message\nwithout one is filed as its text. A repeated Message-Id is acknowledged and\nignored. 406 tells Mailgun not to retry (unknown or retired address, daily\nlimit reached, feature not configured).\nThis endpoint is called by Mailgun, not by API clients.\n\nPublic: no token. Operation: `receiveReceiptEmail`.",
                        "auth": {
                            "type": "noauth"
                        },
                        "body": {
                            "mode": "raw",
                            "raw": "{}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Extract Receipt Data via OCR",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/receipts/ocr",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "receipts",
                                "ocr"
                            ]
                        },
                        "description": "Extract vendor, amount, date, and category from a receipt image using OpenAI Vision.\nAccepts either an image URL or base64-encoded image data.\n\nScope: `write`. Operation: `extractReceiptOcrDirect`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"image_url\": \"https://example.com\",\n    \"image_base64\": \"\"\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Submit OCR Feedback",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/receipts/ocr/feedback",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "receipts",
                                "ocr",
                                "feedback"
                            ]
                        },
                        "description": "Record user feedback or corrections after OCR review for learning improvement.\n\nScope: `write`. Operation: `submitOcrFeedback`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"vendor\": \"Office Depot\",\n    \"suggested_category\": \"Supplies\",\n    \"final_category\": \"Office Supplies\",\n    \"amount\": \"45.99\",\n    \"currency\": \"USD\"\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Upload a receipt image",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/receipts/upload",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "receipts",
                                "upload"
                            ]
                        },
                        "description": "Uploads a receipt image via multipart/form-data. Accepts JPEG, PNG, WebP,\nHEIC, and HEIF formats up to 10 MB. The server validates the file's actual\nMIME type (not the client-provided Content-Type) and stores it in a\ndate-partitioned directory structure.\n\nScope: `write`. Operation: `uploadReceipt`.",
                        "body": {
                            "mode": "formdata",
                            "formdata": [
                                {
                                    "key": "receipt_image",
                                    "type": "file",
                                    "src": [],
                                    "description": "The receipt image file. Accepted MIME types: image/jpeg,\nimage/png, image/webp, image/heic, image/heif. Max size: 10 MB."
                                }
                            ]
                        }
                    },
                    "response": []
                },
                {
                    "name": "Confirm OCR Extraction",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/receipts/:id/confirm",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "receipts",
                                ":id",
                                "confirm"
                            ],
                            "variable": [
                                {
                                    "key": "id",
                                    "value": "1",
                                    "description": "Receipt (attachment) ID"
                                }
                            ]
                        },
                        "description": "Confirm or correct OCR-extracted receipt fields. Merges user corrections with existing\nextraction and persists as user_confirmed with confidence 1.0.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `confirmReceiptOcr`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"vendor\": \"\",\n    \"amount\": 0,\n    \"transaction_date\": \"2026-01-31\",\n    \"category\": \"\"\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Trigger OCR extraction for uploaded receipt",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/receipts/:id/extract",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "receipts",
                                ":id",
                                "extract"
                            ],
                            "variable": [
                                {
                                    "key": "id",
                                    "value": "42",
                                    "description": "Attachment ID of the uploaded receipt"
                                }
                            ]
                        },
                        "description": "Reads the stored image file for an already-uploaded receipt attachment\nand runs OCR extraction via OpenAI Vision API. Persists the result to\n`receipt_extractions`. The path `{id}` is the attachment ID.\n\nReturns the raw extraction, an optional AI categorization suggestion,\nand the normalized `ocr` payload via OcrResultNormalizer.\n\nScope: `write`. Operation: `extractReceiptOcr`."
                    },
                    "response": []
                }
            ]
        },
        {
            "name": "NextBestAction",
            "description": "Deterministic priority ranking of candidate actions. Scores actions by\nimpact, urgency, effort, confidence, and due date. Fully local — no\nexternal API calls.",
            "item": [
                {
                    "name": "Prioritize candidate actions",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/next-best-action",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "next-best-action"
                            ],
                            "query": [
                                {
                                    "key": "one_action",
                                    "value": "0",
                                    "description": "Convenience alias for one_action_mode in the request body",
                                    "disabled": true
                                }
                            ]
                        },
                        "description": "Accepts a list of candidate actions and returns them ranked by\ndeterministic priority score. Supports one-action mode for UIs\nthat only need the single top recommendation.\n\nScoring is fully local (no external API calls). Each action is scored\nbased on impact, urgency, effort, confidence, due date, and blocked status.\n\nScope: `write`. Operation: `prioritizeNextBestAction`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"actions\": [\n        {\n            \"label\": \"Reconcile bank account\",\n            \"impact\": 5,\n            \"urgency\": 4,\n            \"effort\": 3,\n            \"confidence\": 4\n        },\n        {\n            \"label\": \"Send overdue invoice reminder\",\n            \"impact\": 3,\n            \"urgency\": 5,\n            \"effort\": 1,\n            \"confidence\": 5,\n            \"due_date\": \"2026-03-07\"\n        }\n    ],\n    \"one_action_mode\": false,\n    \"limit\": 3\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                }
            ]
        },
        {
            "name": "AI Review",
            "description": "AI suggestion review configuration — get and update confidence thresholds,\nbulk approve suggestions that meet threshold criteria.",
            "item": [
                {
                    "name": "Bulk Approve AI Suggestions",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/ai/review/bulk-approve",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "ai",
                                "review",
                                "bulk-approve"
                            ]
                        },
                        "description": "Approve multiple AI-generated suggestions at once. Each approved\nsuggestion is posted to the ledger through the same path the review\nqueue uses, so a locked period, an inactive account or a bank\ntransaction somebody else already posted refuses that suggestion and\nleaves the rest of the batch alone.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `bulkApproveAiSuggestions`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"ids\": [\n        0\n    ],\n    \"min_confidence\": 0\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Get AI Review Thresholds",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/ai/review/thresholds",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "ai",
                                "review",
                                "thresholds"
                            ]
                        },
                        "description": "Get the current AI suggestion review thresholds for the entity.\n\nScope: `read`. Operation: `getAiReviewThresholds`."
                    },
                    "response": []
                },
                {
                    "name": "Update AI Review Thresholds",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/ai/review/thresholds",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "ai",
                                "review",
                                "thresholds"
                            ]
                        },
                        "description": "Update the AI suggestion review thresholds for the entity.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `updateAiReviewThresholds`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"auto_approve_threshold\": 0.9,\n    \"bulk_approve_threshold\": 0.8\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Pending AI posting suggestions",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/review-queue/pending-ai-suggestions",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "review-queue",
                                "pending-ai-suggestions"
                            ]
                        },
                        "description": "Pending suggestions awaiting review for the caller's entity. Approve and\nreject are not yet exposed over the API: that path posts a journal entry\nand is currently implemented inline in the web controller.\n\nScope: `read`. Operation: `listPendingAiSuggestions`."
                    },
                    "response": []
                },
                {
                    "name": "Approve a posting suggestion",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/review-queue/:suggestionId/approve",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "review-queue",
                                ":suggestionId",
                                "approve"
                            ],
                            "variable": [
                                {
                                    "key": "suggestionId",
                                    "value": "1",
                                    "description": ""
                                }
                            ]
                        },
                        "description": "Posts the suggestion's bank transaction to the ledger as a balanced\njournal entry, marks the bank transaction posted and closes the\nsuggestion. All four writes commit or roll back together.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `approvePostingSuggestion`."
                    },
                    "response": []
                },
                {
                    "name": "Reject a posting suggestion",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/review-queue/:suggestionId/reject",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "review-queue",
                                ":suggestionId",
                                "reject"
                            ],
                            "variable": [
                                {
                                    "key": "suggestionId",
                                    "value": "1",
                                    "description": ""
                                }
                            ]
                        },
                        "description": "Closes the suggestion without posting anything to the ledger.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `rejectPostingSuggestion`."
                    },
                    "response": []
                }
            ]
        },
        {
            "name": "AccountantPackage",
            "description": "Accountant package export — generate ZIP archives containing financial\nreports, general ledger, and trial balance CSVs. Supports date range\nfiltering, batch export, and export lifecycle management.",
            "item": [
                {
                    "name": "Clean Up Old Exports",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/accountant-package/cleanup",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "accountant-package",
                                "cleanup"
                            ]
                        },
                        "description": "Remove old accountant package export files.\n\nScope: `write`. Operation: `cleanupAccountantPackage`."
                    },
                    "response": []
                },
                {
                    "name": "Download Export",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/accountant-package/download/:exportId",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "accountant-package",
                                "download",
                                ":exportId"
                            ],
                            "variable": [
                                {
                                    "key": "exportId",
                                    "value": "1",
                                    "description": "Export ID, as returned by the export endpoints"
                                }
                            ]
                        },
                        "description": "Download a completed accountant package export as a ZIP file.\n\nScope: `read`. Operation: `downloadAccountantPackage`."
                    },
                    "response": []
                },
                {
                    "name": "Export with Custom Options",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/accountant-package/export",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "accountant-package",
                                "export"
                            ]
                        },
                        "description": "Export the accountant package for one entity over a date range. The archive holds general_ledger.csv and trial_balance.csv; both cover the same period, so the trial balance is that period's activity netted per account.\n\nScope: `write`. Operation: `exportAccountantPackageCustom`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"entity_id\": 0,\n    \"date_from\": \"2026-01-31\",\n    \"date_to\": \"2026-01-31\",\n    \"include_gl\": true,\n    \"include_tb\": true\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Export Accountant Package",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/accountant-package/export/:userId?entity_id=",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "accountant-package",
                                "export",
                                ":userId"
                            ],
                            "query": [
                                {
                                    "key": "entity_id",
                                    "value": "",
                                    "description": "(Required) Entity to export. Required — the handler refuses rather than guessing when the caller belongs to more than one entity. An id the caller has no membership in is answered the same way as a bad one.",
                                    "disabled": false
                                }
                            ],
                            "variable": [
                                {
                                    "key": "userId",
                                    "value": "1",
                                    "description": "User ID to export for"
                                }
                            ]
                        },
                        "description": "Generate a ZIP archive holding general_ledger.csv and trial_balance.csv for one entity. userId must be the authenticated caller.\n\nScope: `read`. Operation: `exportAccountantPackage`."
                    },
                    "response": []
                },
                {
                    "name": "List Available Exports",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/accountant-package/list/:userId",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "accountant-package",
                                "list",
                                ":userId"
                            ],
                            "variable": [
                                {
                                    "key": "userId",
                                    "value": "1",
                                    "description": "User ID"
                                }
                            ]
                        },
                        "description": "List all available accountant package exports for a user.\n\nScope: `read`. Operation: `listAccountantPackages`."
                    },
                    "response": []
                },
                {
                    "name": "Check Export Status",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/accountant-package/status/:exportId",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "accountant-package",
                                "status",
                                ":exportId"
                            ],
                            "variable": [
                                {
                                    "key": "exportId",
                                    "value": "1",
                                    "description": "Export ID, as returned by the export endpoints"
                                }
                            ]
                        },
                        "description": "Check the status of an accountant package export.\n\nScope: `read`. Operation: `getAccountantPackageStatus`."
                    },
                    "response": []
                },
                {
                    "name": "Delete Export",
                    "request": {
                        "method": "DELETE",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/accountant-package/:exportId",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "accountant-package",
                                ":exportId"
                            ],
                            "variable": [
                                {
                                    "key": "exportId",
                                    "value": "1",
                                    "description": "Export ID, as returned by the export endpoints"
                                }
                            ]
                        },
                        "description": "Delete a specific accountant package export.\n\nScope: `write`. Operation: `deleteAccountantPackage`."
                    },
                    "response": []
                }
            ]
        },
        {
            "name": "Plaid",
            "description": "Plaid banking integration — webhook health monitoring, webhook replay\nfor debugging, and the inbound webhook receiver (signature-verified,\nno bearer auth). Supports sandbox and production environments.",
            "item": [
                {
                    "name": "Plaid Webhook Receiver",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/plaid/webhook",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "plaid",
                                "webhook"
                            ]
                        },
                        "description": "Receives webhooks from Plaid. Uses JWT signature verification (not bearer token auth).\nThis endpoint is called directly by Plaid's servers.\n\nPublic: no token. Operation: `receivePlaidWebhook`.",
                        "auth": {
                            "type": "noauth"
                        },
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"webhook_type\": \"\",\n    \"webhook_code\": \"\",\n    \"item_id\": \"\"\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Plaid Webhook Health",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/plaid/webhook/health",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "plaid",
                                "webhook",
                                "health"
                            ]
                        },
                        "description": "Check the health status of Plaid webhook processing.\n\nScope: `read`. Operation: `getPlaidWebhookHealth`."
                    },
                    "response": []
                },
                {
                    "name": "Replay Plaid Webhook",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/plaid/webhook/replay/:webhookId",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "plaid",
                                "webhook",
                                "replay",
                                ":webhookId"
                            ],
                            "variable": [
                                {
                                    "key": "webhookId",
                                    "value": "1",
                                    "description": "Webhook log ID to replay"
                                }
                            ]
                        },
                        "description": "Replay a previously received Plaid webhook for reprocessing.\n\nScope: `write`. Operation: `replayPlaidWebhook`."
                    },
                    "response": []
                }
            ]
        },
        {
            "name": "Tax",
            "description": "Tax estimation endpoints — quarterly estimated tax projections based on\nP&L snapshots, with IRS safe-harbour annualization.",
            "item": [
                {
                    "name": "Tax Dashboard",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/tax/dashboard",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "tax",
                                "dashboard"
                            ],
                            "query": [
                                {
                                    "key": "cash_reserved_for_tax",
                                    "value": "",
                                    "description": "Cash already set aside for tax; \"1,500.00\" is accepted.",
                                    "disabled": true
                                }
                            ]
                        },
                        "description": "Get the tax dashboard for the authenticated user's active entity.\nReturns upcoming tax deadlines, reminders, quarterly estimates,\nand exposure details for the current tax period.\n\nScope: `read`. Operation: `getTaxDashboard`."
                    },
                    "response": []
                }
            ]
        },
        {
            "name": "Statements",
            "description": "Statement import pipeline — upload PDF/CSV/OFX/QFX bank and credit-card\nstatements, extract transactions (pdftotext + OpenAI Vision fallback for\nPDFs; hand-rolled parsers for CSV/OFX/QFX), apply PostingRule suggestions,\nflag duplicates against existing bank_transactions, review and commit.\nCommitted lines flow into bank_transactions so the review queue and\nreconciliation pipeline handle them identically to Plaid-sourced rows.",
            "item": [
                {
                    "name": "List statement imports for the authenticated entity",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "X-Entity-Id",
                                "value": "",
                                "description": "",
                                "disabled": true
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/statements",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "statements"
                            ]
                        },
                        "description": "List statement imports for the authenticated entity\n\nScope: `read`. Operation: `listStatements`."
                    },
                    "response": []
                },
                {
                    "name": "Upload a bank or credit card statement",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "X-Entity-Id",
                                "value": "",
                                "description": "",
                                "disabled": true
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/statements/upload",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "statements",
                                "upload"
                            ]
                        },
                        "description": "Accepts a multipart/form-data upload (field name \"statement\") of a PDF,\nCSV, OFX, or QFX statement (20 MB max). The server computes a SHA-256\nhash for dedup, stores the file outside the web root, and kicks off\nextraction synchronously. Returns the new statement_import id plus\nextraction summary. Requires PDF extraction support (pdftotext on PATH\nor OPENAI_API_KEY) to accept PDFs; CSV/OFX/QFX always work.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `uploadStatement`.",
                        "body": {
                            "mode": "formdata",
                            "formdata": [
                                {
                                    "key": "statement",
                                    "type": "file",
                                    "src": [],
                                    "description": "PDF/CSV/OFX/QFX file, max 20 MB."
                                },
                                {
                                    "key": "account_id",
                                    "type": "text",
                                    "value": "",
                                    "description": "Optional target account to pre-bind."
                                }
                            ]
                        }
                    },
                    "response": []
                },
                {
                    "name": "Reject and cancel a statement import",
                    "request": {
                        "method": "DELETE",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/statements/:id",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "statements",
                                ":id"
                            ],
                            "variable": [
                                {
                                    "key": "id",
                                    "value": "1",
                                    "description": ""
                                }
                            ]
                        },
                        "description": "Soft-cancels the import (sets status=rejected). Does not delete the stored file. Committed imports cannot be rejected.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `deleteStatement`."
                    },
                    "response": []
                },
                {
                    "name": "Get a single statement import with its extracted lines",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/statements/:id",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "statements",
                                ":id"
                            ],
                            "variable": [
                                {
                                    "key": "id",
                                    "value": "1",
                                    "description": ""
                                }
                            ]
                        },
                        "description": "Get a single statement import with its extracted lines\n\nScope: `read`. Operation: `getStatement`."
                    },
                    "response": []
                },
                {
                    "name": "Bulk auto-approve high-confidence pending lines",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/statements/:id/auto-approve",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "statements",
                                ":id",
                                "auto-approve"
                            ],
                            "variable": [
                                {
                                    "key": "id",
                                    "value": "1",
                                    "description": "Statement import ID"
                                }
                            ]
                        },
                        "description": "Finds all pending statement_import_lines for this import whose canonical\n`confidence` score is >= 0.80 and promotes them to `confirmed`, copying\n`suggested_account_id` into `user_confirmed_account_id` when the user has\nnot already made a manual choice. Returns the count approved and the\nremaining pending count so the caller can decide whether to follow up with\n`import-ready` or handle the residual lines interactively.\n\nRequires the import to be in a non-committed state.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `autoApproveStatement`."
                    },
                    "response": []
                },
                {
                    "name": "Commit a reviewed statement import into bank_transactions",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/statements/:id/commit",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "statements",
                                ":id",
                                "commit"
                            ],
                            "variable": [
                                {
                                    "key": "id",
                                    "value": "1",
                                    "description": ""
                                }
                            ]
                        },
                        "description": "Inserts each confirmed line into bank_transactions. A line's category\n(the account the user chose, else the rule or AI suggestion) becomes a\npending posting suggestion for the new row in the review queue;\n`categorized` counts them. Each confirmed line is re-checked against the\naccount's existing bank transactions (same date and amount) and marked\nduplicate instead of inserted when one matches, unless the user\nconfirmed it despite an earlier duplicate flag; `duplicates` counts them.\nThe commit is refused (422, nothing written) when a confirmed line has\nno valid date. The body may include account_id to bind the target\naccount if not set, and approve_pending=true to flip still-pending\ndated lines to confirmed before committing.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `commitStatement`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"account_id\": 0,\n    \"approve_pending\": false\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Auto-approve and commit a reviewed statement import",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/statements/:id/import-ready",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "statements",
                                ":id",
                                "import-ready"
                            ],
                            "variable": [
                                {
                                    "key": "id",
                                    "value": "1",
                                    "description": "Statement import ID"
                                }
                            ]
                        },
                        "description": "Combines two steps in a single call:\n1. Auto-approve — promotes all pending lines with confidence >= 0.80 to\n   `confirmed` (same logic as `auto-approve` endpoint).\n2. Commit — inserts each confirmed line into `bank_transactions` so the\n   existing posting-rules and reconciliation pipeline can pick them up.\n\nIf commit fails but auto-approve succeeded, the response is still `ok: true`\nwith a `warnings` array containing a `COMMIT_PARTIAL` entry so the caller\ncan surface the partial state and let the user retry.\n\nReturns `remaining_unmapped` (pending lines that still have no account\nassigned) so the UI can prompt the user to handle them before retrying.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `importReadyStatement`."
                    },
                    "response": []
                },
                {
                    "name": "Assign one account to multiple statement lines",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/statements/:id/lines/bulk-assign",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "statements",
                                ":id",
                                "lines",
                                "bulk-assign"
                            ],
                            "variable": [
                                {
                                    "key": "id",
                                    "value": "1",
                                    "description": "Statement import ID"
                                }
                            ]
                        },
                        "description": "Sets `user_confirmed_account_id` to `account_id` on each line in `line_ids`\nand transitions them to `confirmed` status. Lines already in `committed` or\n`skipped` status are excluded. The `account_id` must belong to the current\nentity. Useful for batch-categorizing a group of similar transactions from\nthe review UI.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `bulkAssignStatementLines`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"line_ids\": [\n        42,\n        43,\n        44\n    ],\n    \"account_id\": 17\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Update a single extracted line during review",
                    "request": {
                        "method": "PUT",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/statements/:id/lines/:lineId",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "statements",
                                ":id",
                                "lines",
                                ":lineId"
                            ],
                            "variable": [
                                {
                                    "key": "id",
                                    "value": "1",
                                    "description": ""
                                },
                                {
                                    "key": "lineId",
                                    "value": "1",
                                    "description": ""
                                }
                            ]
                        },
                        "description": "Partial update for a statement_import_line. Accepts txn_date, description,\namount_cents, user_confirmed_account_id, and status (pending|confirmed|skipped).\nCommitted lines cannot be updated.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `updateStatementLine`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"txn_date\": \"2026-01-31\",\n    \"description\": \"\",\n    \"amount_cents\": 0,\n    \"user_confirmed_account_id\": 0,\n    \"status\": \"pending\"\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Re-run extraction for an existing statement import",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/statements/:id/reparse",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "statements",
                                ":id",
                                "reparse"
                            ],
                            "variable": [
                                {
                                    "key": "id",
                                    "value": "1",
                                    "description": ""
                                }
                            ]
                        },
                        "description": "Re-runs extraction from the stored file and replaces this import's\nstatement_import_lines only when it succeeds; a failed reparse keeps the\nexisting lines and sets the import to failed. Useful after creating new\nPostingRules or changing the target account. Cannot reparse a committed\nimport.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `reparseStatement`."
                    },
                    "response": []
                }
            ]
        },
        {
            "name": "Entities",
            "description": "Entities the caller belongs to, and which one their requests act on.",
            "item": [
                {
                    "name": "List the caller's entities",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/entities",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "entities"
                            ]
                        },
                        "description": "Entities the caller is a member of, with the active one flagged.\n\nScope: `read`. Operation: `listEntities`."
                    },
                    "response": []
                },
                {
                    "name": "Set the active entity",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/entities/switch",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "entities",
                                "switch"
                            ]
                        },
                        "description": "Persists which entity the caller is working in. Endpoints that do not name\nan entity act on it afterwards. Refused with 403 if the caller is not a\nmember, and a stored choice is ignored if that membership later ends.\n\nScope: `read`. Operation: `switchActiveEntity`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"entity_id\": 0\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                }
            ]
        },
        {
            "name": "Mobile",
            "description": "Endpoints used only by the mobile client, such as push registration.",
            "item": [
                {
                    "name": "Register a device for push notifications",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/mobile/push/register",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "mobile",
                                "push",
                                "register"
                            ]
                        },
                        "description": "Stores the client's push token. Re-registering the same token updates the\nexisting registration rather than creating a duplicate. Storage only --\ndelivery requires a push provider to be configured.\n\nScope: `read`. Operation: `registerPushDevice`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"push_token\": \"\",\n    \"platform\": \"ios\",\n    \"device_name\": \"\",\n    \"app_version\": \"\"\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Stop push notifications for a device",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/mobile/push/unregister",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "mobile",
                                "push",
                                "unregister"
                            ]
                        },
                        "description": "Revokes the caller's own registration for the given token.\n\nScope: `read`. Operation: `unregisterPushDevice`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"push_token\": \"\"\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Which push notifications the caller receives",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/notification-preferences",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "notification-preferences"
                            ]
                        },
                        "description": "Every notification type with its current state and a human label, so a\nsettings screen can be built without hardcoding the list.\n\nScope: `read`. Operation: `getNotificationPreferences`."
                    },
                    "response": []
                },
                {
                    "name": "Change which push notifications the caller receives",
                    "request": {
                        "method": "PUT",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/notification-preferences",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "notification-preferences"
                            ]
                        },
                        "description": "Send only the switches being changed; anything omitted is left alone, so\none device toggling a setting cannot clobber another's change. Values may\nbe booleans or the usual string forms.\n\nScope: `read`. Operation: `updateNotificationPreferences`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"notify_invoice_paid\": true,\n    \"digest_frequency\": \"weekly\"\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                }
            ]
        },
        {
            "name": "ChartOfAccountsImport",
            "description": "Chart-of-accounts import pipeline: upload a COA file, review and correct the\nparsed lines, then commit them into the chart of accounts.",
            "item": [
                {
                    "name": "List chart-of-accounts imports",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/coa-imports",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "coa-imports"
                            ]
                        },
                        "description": "Returns the COA import batches for the authenticated entity, newest first.\n\nScope: `read`. Operation: `listCoaImports`."
                    },
                    "response": []
                },
                {
                    "name": "Upload a chart-of-accounts file",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/coa-imports/upload",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "coa-imports",
                                "upload"
                            ]
                        },
                        "description": "Accepts a CSV/XLSX chart of accounts and parses it into reviewable import lines.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `uploadCoaImport`.",
                        "body": {
                            "mode": "formdata",
                            "formdata": [
                                {
                                    "key": "file",
                                    "type": "file",
                                    "src": [],
                                    "description": "Chart-of-accounts file (CSV or XLSX)"
                                }
                            ]
                        }
                    },
                    "response": []
                },
                {
                    "name": "Delete a chart-of-accounts import",
                    "request": {
                        "method": "DELETE",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/coa-imports/:id",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "coa-imports",
                                ":id"
                            ],
                            "variable": [
                                {
                                    "key": "id",
                                    "value": "1",
                                    "description": "Import batch ID"
                                }
                            ]
                        },
                        "description": "Discards an uncommitted import batch and its lines.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `deleteCoaImport`."
                    },
                    "response": []
                },
                {
                    "name": "Get a chart-of-accounts import",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/coa-imports/:id",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "coa-imports",
                                ":id"
                            ],
                            "variable": [
                                {
                                    "key": "id",
                                    "value": "1",
                                    "description": "Import batch ID"
                                }
                            ]
                        },
                        "description": "Returns one import batch with its parsed lines and review status.\n\nScope: `read`. Operation: `getCoaImport`."
                    },
                    "response": []
                },
                {
                    "name": "Auto-approve high-confidence lines",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/coa-imports/:id/auto-approve",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "coa-imports",
                                ":id",
                                "auto-approve"
                            ],
                            "variable": [
                                {
                                    "key": "id",
                                    "value": "1",
                                    "description": "Import batch ID"
                                }
                            ]
                        },
                        "description": "Confirms every line whose parsed mapping meets the confidence threshold, leaving the rest for manual review.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `autoApproveCoaImport`."
                    },
                    "response": []
                },
                {
                    "name": "Commit a chart-of-accounts import",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/coa-imports/:id/commit",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "coa-imports",
                                ":id",
                                "commit"
                            ],
                            "variable": [
                                {
                                    "key": "id",
                                    "value": "1",
                                    "description": "Import batch ID"
                                }
                            ]
                        },
                        "description": "Creates the confirmed accounts in the chart of accounts. Idempotent per import batch.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `commitCoaImport`."
                    },
                    "response": []
                },
                {
                    "name": "Check whether an import is ready to commit",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/coa-imports/:id/import-ready",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "coa-imports",
                                ":id",
                                "import-ready"
                            ],
                            "variable": [
                                {
                                    "key": "id",
                                    "value": "1",
                                    "description": "Import batch ID"
                                }
                            ]
                        },
                        "description": "Reports outstanding validation problems and whether every line has been reviewed.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `coaImportReady`."
                    },
                    "response": []
                },
                {
                    "name": "Bulk-confirm import lines",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/coa-imports/:id/lines/bulk-confirm",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "coa-imports",
                                ":id",
                                "lines",
                                "bulk-confirm"
                            ],
                            "variable": [
                                {
                                    "key": "id",
                                    "value": "1",
                                    "description": "Import batch ID"
                                }
                            ]
                        },
                        "description": "Marks the given import lines as confirmed so they are included at commit.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `bulkConfirmCoaImportLines`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"line_ids\": [\n        0\n    ]\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Bulk-skip import lines",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/coa-imports/:id/lines/bulk-skip",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "coa-imports",
                                ":id",
                                "lines",
                                "bulk-skip"
                            ],
                            "variable": [
                                {
                                    "key": "id",
                                    "value": "1",
                                    "description": "Import batch ID"
                                }
                            ]
                        },
                        "description": "Marks the given import lines as skipped so they are excluded at commit.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `bulkSkipCoaImportLines`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"line_ids\": [\n        0\n    ]\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Update a single import line",
                    "request": {
                        "method": "PUT",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/coa-imports/:id/lines/:lineId",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "coa-imports",
                                ":id",
                                "lines",
                                ":lineId"
                            ],
                            "variable": [
                                {
                                    "key": "id",
                                    "value": "1",
                                    "description": "Import batch ID"
                                },
                                {
                                    "key": "lineId",
                                    "value": "1",
                                    "description": "Import line ID"
                                }
                            ]
                        },
                        "description": "Corrects the account code, name, type or mapping on one parsed line before commit.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `updateCoaImportLine`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"name\": \"Operating Checking\",\n    \"type\": \"asset\",\n    \"subtype\": \"bank\",\n    \"status\": \"confirmed\"\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Re-parse an uploaded import file",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/coa-imports/:id/reparse",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "coa-imports",
                                ":id",
                                "reparse"
                            ],
                            "variable": [
                                {
                                    "key": "id",
                                    "value": "1",
                                    "description": "Import batch ID"
                                }
                            ]
                        },
                        "description": "Discards the current parsed lines and re-runs parsing against the stored upload.\n\nScope: `write`. Roles: owner, bookkeeper. Operation: `reparseCoaImport`."
                    },
                    "response": []
                }
            ]
        },
        {
            "name": "MonthEndClose",
            "description": "Month-end close: period totals and checklist state used to verify the books\nare ready to close.",
            "item": [
                {
                    "name": "Month-end close summary",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/month-end-close/summary?start_date=2026-08-01&end_date=2026-08-31",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "month-end-close",
                                "summary"
                            ],
                            "query": [
                                {
                                    "key": "start_date",
                                    "value": "2026-08-01",
                                    "description": "(Required) First day of the close period, Y-m-d.",
                                    "disabled": false
                                },
                                {
                                    "key": "end_date",
                                    "value": "2026-08-31",
                                    "description": "(Required) Last day of the close period, Y-m-d. Must be on or after start_date.",
                                    "disabled": false
                                },
                                {
                                    "key": "include_unposted",
                                    "value": "1",
                                    "description": "Send \"1\" to include unposted transactions in the totals. Any other value is treated as off.",
                                    "disabled": true
                                }
                            ]
                        },
                        "description": "Entity-scoped totals and checklist state for the requested close period.\n\nScope: `read`. Operation: `getMonthEndCloseSummary`."
                    },
                    "response": []
                }
            ]
        },
        {
            "name": "Webhook Endpoints",
            "description": "Outbound webhook subscriptions: register a URL, choose the events (invoice.created, invoice.paid,\nbill.paid, transaction.created), read the delivery log. Owner only. See the Webhooks section of the\nAPI description for the delivery format and signature.",
            "item": [
                {
                    "name": "List Webhook Endpoints",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/webhooks/endpoints",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "webhooks",
                                "endpoints"
                            ]
                        },
                        "description": "The business's outbound webhook subscriptions, newest first. A business may hold 10. The signing secret\nis not part of the listing; it is shown once, when the endpoint is created. Owner only.\n\nScope: `read`. Roles: owner. Operation: `listWebhookEndpoints`."
                    },
                    "response": []
                },
                {
                    "name": "Create Webhook Endpoint",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/webhooks/endpoints",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "webhooks",
                                "endpoints"
                            ]
                        },
                        "description": "Subscribe a URL to events. The URL must be `https` and resolve to a public address, both now and each\ntime an event is sent. The response carries the signing secret, **once**: store it now, it cannot be read\nback. See \"Webhooks\" in the API description for the delivery format and how to verify a signature.\nOwner only.\n\nScope: `write`. Roles: owner. Operation: `createWebhookEndpoint`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"name\": \"Back office\",\n    \"url\": \"https://example.com/hooks/hassle-free-books\",\n    \"event_types\": [\n        \"invoice.paid\",\n        \"bill.paid\"\n    ]\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Delete Webhook Endpoint",
                    "request": {
                        "method": "DELETE",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/webhooks/endpoints/:id",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "webhooks",
                                "endpoints",
                                ":id"
                            ],
                            "variable": [
                                {
                                    "key": "id",
                                    "value": "1",
                                    "description": "Webhook endpoint ID"
                                }
                            ]
                        },
                        "description": "Remove the subscription. Deliveries still queued for it stop. Owner only.\n\nScope: `write`. Roles: owner. Operation: `deleteWebhookEndpoint`."
                    },
                    "response": []
                },
                {
                    "name": "Get Webhook Endpoint",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/webhooks/endpoints/:id",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "webhooks",
                                "endpoints",
                                ":id"
                            ],
                            "variable": [
                                {
                                    "key": "id",
                                    "value": "1",
                                    "description": "Webhook endpoint ID"
                                }
                            ]
                        },
                        "description": "One subscription. Another business's endpoint is 404, not 403. Owner only.\n\nScope: `read`. Roles: owner. Operation: `getWebhookEndpoint`."
                    },
                    "response": []
                },
                {
                    "name": "Update Webhook Endpoint",
                    "request": {
                        "method": "PUT",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/webhooks/endpoints/:id",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "webhooks",
                                "endpoints",
                                ":id"
                            ],
                            "variable": [
                                {
                                    "key": "id",
                                    "value": "1",
                                    "description": "Webhook endpoint ID"
                                }
                            ]
                        },
                        "description": "Change any of `name`, `url`, `event_types` and `is_active`; fields left out are unchanged. A new URL\ngoes through the same https and public-address checks as at creation. The secret cannot be changed or\nread; to rotate it, create a new endpoint and delete the old one. Owner only.\n\nScope: `write`. Roles: owner. Operation: `updateWebhookEndpoint`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"is_active\": false\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "List Webhook Deliveries",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/webhooks/endpoints/:id/deliveries",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "webhooks",
                                "endpoints",
                                ":id",
                                "deliveries"
                            ],
                            "query": [
                                {
                                    "key": "limit",
                                    "value": "50",
                                    "description": "Rows per page (1 to 200).",
                                    "disabled": true
                                },
                                {
                                    "key": "offset",
                                    "value": "0",
                                    "description": "Rows to skip.",
                                    "disabled": true
                                }
                            ],
                            "variable": [
                                {
                                    "key": "id",
                                    "value": "1",
                                    "description": "Webhook endpoint ID"
                                }
                            ]
                        },
                        "description": "Every delivery to this endpoint, newest first, with its status, number of attempts and what your server\nanswered. Use it to find out why an event did not arrive. Owner only.\n\nScope: `read`. Roles: owner. Operation: `listWebhookDeliveries`."
                    },
                    "response": []
                },
                {
                    "name": "List Webhook Event Types",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/webhooks/event-types",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "webhooks",
                                "event-types"
                            ]
                        },
                        "description": "The events a webhook subscription can name, and how deliveries are made (method, headers, signature).\nStatic: it does not depend on the caller's data. Owner only.\n\nScope: `read`. Roles: owner. Operation: `listWebhookEventTypes`."
                    },
                    "response": []
                }
            ]
        },
        {
            "name": "Bank Connections",
            "description": "Connected bank accounts (Plaid) and on-demand sync.",
            "item": [
                {
                    "name": "List Bank Connections",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/bank/connections",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "bank",
                                "connections"
                            ]
                        },
                        "description": "Returns all bank connections for the authenticated user's active entity.\nEach connection includes normalized status fields and lifecycle flags consumed\nby the Flutter BankConnectionsService.\n\nEntity scope is automatically derived from the authenticated user's memberships.\nAn explicit entity can be selected via the `X-Entity-Id` header, `entity_id`\nquery parameter, or `entity_id` JSON body field (in that priority order).\n\nScope: `read`. Operation: `listBankConnections`."
                    },
                    "response": []
                },
                {
                    "name": "Trigger Bank Connection Sync",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/bank/connections/:id/sync",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "bank",
                                "connections",
                                ":id",
                                "sync"
                            ],
                            "variable": [
                                {
                                    "key": "id",
                                    "value": "42",
                                    "description": "Bank connection ID to sync"
                                }
                            ]
                        },
                        "description": "Flags a bank connection for an immediate sync by setting `needs_sync = true`\non the connection row. The actual sync is performed asynchronously by the\nPlaid webhook / background sync process.\n\nSync is blocked when the connection status is `syncing` (already in progress)\nor `needs_reauth` (user must re-authenticate via Plaid Link update mode).\nThis lifecycle gate mirrors `BankConnection.canSync` in the Flutter client.\n\nScope: `write`. Operation: `triggerBankConnectionSync`."
                    },
                    "response": []
                }
            ]
        },
        {
            "name": "Merchant Connections",
            "description": "Payment-processor data (Stripe, PayPal, Square, Shopify, Etsy, custom feeds): connections, activity and the\nsales/fee/payout report, read-only. Connecting and posting are done in the web app. The inbound webhook\nreceivers of each provider are listed here too; they are verified by the provider's signature, not a token.",
            "item": [
                {
                    "name": "List Merchant Activity",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/merchant/activity",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "merchant",
                                "activity"
                            ],
                            "query": [
                                {
                                    "key": "connection_id",
                                    "value": "",
                                    "description": "Limit to one connection",
                                    "disabled": true
                                },
                                {
                                    "key": "type",
                                    "value": "",
                                    "description": "Line type filter",
                                    "disabled": true
                                },
                                {
                                    "key": "page",
                                    "value": "",
                                    "description": "Page number",
                                    "disabled": true
                                }
                            ]
                        },
                        "description": "Imported processor lines: sales, fees, refunds, disputes and payouts, newest first.\nRead-only. Connecting, syncing, posting and disconnecting are web-only. Money is integer cents\nplus an exact decimal string; no secret or token is ever returned.\n\nScope: `read`. Operation: `listMerchantActivity`."
                    },
                    "response": []
                },
                {
                    "name": "Cin7 Core Webhook Receiver",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/merchant/cin7/webhook",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "merchant",
                                "cin7",
                                "webhook"
                            ]
                        },
                        "description": "Receives the Cin7 Core webhooks HassleFreeBooks registers for a connected Cin7 Core account (sale shipments,\ninvoices, credit notes, voids and undos; purchase receipts, invoices and credit notes). The URL carries the\nconnection's token (?t=), and Cin7 sends the per-connection bearer secret we gave it as the Authorization\nheader (Cin7 Core does not sign payloads). The event only prompts a sync of that connection; cost of goods\nsold and stock movements are read from Cin7 Core's own journals, never from the payload.\nNot bearer-authenticated by an HFB key: the provider's credential is checked, and an\nunverifiable request is refused with 401 before anything is stored. Deliveries\nare replay-safe; a repeated delivery is acknowledged and ignored.\nThis endpoint is called directly by Cin7 Core's servers.\n\nPublic: no token. Operation: `receiveCin7MerchantWebhook`.",
                        "auth": {
                            "type": "noauth"
                        },
                        "body": {
                            "mode": "raw",
                            "raw": "{}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "List Merchant Connections",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/merchant/connections",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "merchant",
                                "connections"
                            ]
                        },
                        "description": "Connected payment processors (Stripe, PayPal, Square, ...) with totals and what needs attention.\nRead-only. Connecting, syncing, posting and disconnecting are web-only. Money is integer cents\nplus an exact decimal string; no secret or token is ever returned.\n\nScope: `read`. Operation: `listMerchantConnections`."
                    },
                    "response": []
                },
                {
                    "name": "Custom Webhook Receiver",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/merchant/custom/webhook",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "merchant",
                                "custom",
                                "webhook"
                            ]
                        },
                        "description": "Receives activity pushed by a custom feed (the URL carries the feed's token, ?t=). Verified with the X-HFB-Signature header (hex HMAC-SHA256 of \"timestamp.body\" with the feed's own signing secret) and X-HFB-Timestamp.\nNot bearer-authenticated: the provider's signature is the credential, and an\nunverifiable request is refused with 401 before anything is stored. Deliveries\nare replay-safe; a repeated event id is acknowledged and ignored.\nThis endpoint is called directly by the system sending the feed.\n\nPublic: no token. Operation: `receiveCustomMerchantWebhook`.",
                        "auth": {
                            "type": "noauth"
                        },
                        "body": {
                            "mode": "raw",
                            "raw": "{}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Etsy Webhook Receiver",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/merchant/etsy/webhook",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "merchant",
                                "etsy",
                                "webhook"
                            ]
                        },
                        "description": "Receives Etsy Open API webhooks (order.paid, order.shipped, ...) for a connected Etsy shop. Verified with the\nStandard Webhooks headers webhook-id, webhook-timestamp and webhook-signature (base64 HMAC-SHA256 of\n\"webhook-id.webhook-timestamp.body\" with the Webhook Portal signing secret; five-minute timestamp tolerance).\nThe event only prompts a sync of the connection whose shop_id it names; the ledger is read from Etsy, never from the payload.\nNot bearer-authenticated: the provider's signature is the credential, and an\nunverifiable request is refused with 401 before anything is stored. Deliveries\nare replay-safe; a repeated webhook-id is acknowledged and ignored.\nThis endpoint is called directly by Etsy's servers.\n\nPublic: no token. Operation: `receiveEtsyMerchantWebhook`.",
                        "auth": {
                            "type": "noauth"
                        },
                        "body": {
                            "mode": "raw",
                            "raw": "{}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Katana Webhook Receiver",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/merchant/katana/webhook",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "merchant",
                                "katana",
                                "webhook"
                            ]
                        },
                        "description": "Receives the Katana webhook HassleFreeBooks registers for a connected Katana account (sales order delivered,\npurchase order received, outsourced purchase order received, manufacturing order done). The URL carries the\nconnection's token (?t=); the x-sha2-signature header is the hex HMAC-SHA256 of the raw body with the token\nKatana issued for that webhook. The event only prompts a sync; cost of goods sold and stock movements are read\nfrom Katana's inventory movements, never from the payload.\nNot bearer-authenticated by an HFB key: the provider's credential is checked, and an\nunverifiable request is refused with 401 before anything is stored. Deliveries\nare replay-safe; a repeated delivery is acknowledged and ignored.\nThis endpoint is called directly by Katana's servers.\n\nPublic: no token. Operation: `receiveKatanaMerchantWebhook`.",
                        "auth": {
                            "type": "noauth"
                        },
                        "body": {
                            "mode": "raw",
                            "raw": "{}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "PayPal Webhook Receiver",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/merchant/paypal/webhook",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "merchant",
                                "paypal",
                                "webhook"
                            ]
                        },
                        "description": "Receives webhooks from PayPal for a connected merchant account. Verified through PayPal's verify-webhook-signature API using the connection's own app; the connection is identified by the `t` query token in the URL we issued.\nNot bearer-authenticated: the provider's signature is the credential, and an\nunverifiable request is refused with 401 before anything is stored. Deliveries\nare replay-safe; a repeated event id is acknowledged and ignored.\nThis endpoint is called directly by PayPal's servers.\n\nPublic: no token. Operation: `receivePayPalMerchantWebhook`.",
                        "auth": {
                            "type": "noauth"
                        },
                        "body": {
                            "mode": "raw",
                            "raw": "{}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Merchant Monthly Report",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/merchant/report",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "merchant",
                                "report"
                            ],
                            "query": [
                                {
                                    "key": "from",
                                    "value": "",
                                    "description": "Start date (Y-m-d)",
                                    "disabled": true
                                },
                                {
                                    "key": "to",
                                    "value": "",
                                    "description": "End date (Y-m-d)",
                                    "disabled": true
                                }
                            ]
                        },
                        "description": "Gross sales, fees, refunds, disputes, net and payouts by month and connection.\nRead-only. Connecting, syncing, posting and disconnecting are web-only. Money is integer cents\nplus an exact decimal string; no secret or token is ever returned.\n\nScope: `read`. Operation: `getMerchantReport`."
                    },
                    "response": []
                },
                {
                    "name": "Sales Tax by State",
                    "request": {
                        "method": "GET",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/merchant/sales-tax",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "merchant",
                                "sales-tax"
                            ],
                            "query": [
                                {
                                    "key": "from",
                                    "value": "",
                                    "description": "First month (Y-m), default January of this year",
                                    "disabled": true
                                },
                                {
                                    "key": "to",
                                    "value": "",
                                    "description": "Last month (Y-m), default this month",
                                    "disabled": true
                                }
                            ]
                        },
                        "description": "Sales tax collected, refunded, net, paid to the state (Avalara Managed Returns only), recorded in\nSales Tax Payable and not yet recorded, by connected sales-tax engine (Avalara AvaTax, TaxJar) and state,\nfor months from..to, plus the business's Sales Tax Payable balance. Read-only: connecting and recording a\nmonth in the books are web-only. Money is integer cents plus an exact decimal string; no key or token is ever returned.\n\nScope: `read`. Operation: `getMerchantSalesTax`."
                    },
                    "response": []
                },
                {
                    "name": "Shopify Webhook Receiver",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/merchant/shopify/webhook",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "merchant",
                                "shopify",
                                "webhook"
                            ]
                        },
                        "description": "Receives webhooks from Shopify for a connected merchant account. Verified with the X-Shopify-Hmac-Sha256 header (base64 HMAC-SHA256 of the raw body with the app secret).\nNot bearer-authenticated: the provider's signature is the credential, and an\nunverifiable request is refused with 401 before anything is stored. Deliveries\nare replay-safe; a repeated event id is acknowledged and ignored.\nThis endpoint is called directly by Shopify's servers.\n\nPublic: no token. Operation: `receiveShopifyMerchantWebhook`.",
                        "auth": {
                            "type": "noauth"
                        },
                        "body": {
                            "mode": "raw",
                            "raw": "{}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Square Webhook Receiver",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/merchant/square/webhook",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "merchant",
                                "square",
                                "webhook"
                            ]
                        },
                        "description": "Receives webhooks from Square for a connected merchant account. Verified with the x-square-hmacsha256-signature header (HMAC-SHA256 over the notification URL and body).\nNot bearer-authenticated: the provider's signature is the credential, and an\nunverifiable request is refused with 401 before anything is stored. Deliveries\nare replay-safe; a repeated event id is acknowledged and ignored.\nThis endpoint is called directly by Square's servers.\n\nPublic: no token. Operation: `receiveSquareMerchantWebhook`.",
                        "auth": {
                            "type": "noauth"
                        },
                        "body": {
                            "mode": "raw",
                            "raw": "{}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                },
                {
                    "name": "Stripe Webhook Receiver",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/merchant/stripe/webhook",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "merchant",
                                "stripe",
                                "webhook"
                            ]
                        },
                        "description": "Receives webhooks from Stripe for a connected merchant account. Verified with the Stripe-Signature HMAC-SHA256 header and a five minute timestamp tolerance.\nNot bearer-authenticated: the provider's signature is the credential, and an\nunverifiable request is refused with 401 before anything is stored. Deliveries\nare replay-safe; a repeated event id is acknowledged and ignored.\nThis endpoint is called directly by Stripe's servers.\n\nPublic: no token. Operation: `receiveStripeMerchantWebhook`.",
                        "auth": {
                            "type": "noauth"
                        },
                        "body": {
                            "mode": "raw",
                            "raw": "{}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                }
            ]
        },
        {
            "name": "Chat",
            "description": "The bookkeeping assistant. Needs an OpenAI key on the deployment; without one it answers 503 CHAT_NOT_CONFIGURED.",
            "item": [
                {
                    "name": "AI-powered bookkeeping Q&A",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Accept",
                                "value": "application/json"
                            },
                            {
                                "key": "Content-Type",
                                "value": "application/json"
                            }
                        ],
                        "url": {
                            "raw": "{{baseUrl}}/api/v1/chat",
                            "host": [
                                "{{baseUrl}}"
                            ],
                            "path": [
                                "api",
                                "v1",
                                "chat"
                            ]
                        },
                        "description": "Send a bookkeeping question and receive an AI-generated answer.\nSupports optional conversation history for multi-turn context.\n\nThe service runs a deterministic intent parser first (e.g. for\nspend reports via the general ledger) before falling back to an\nLLM-backed response. Entity context is required for scoped queries.\n\nIf the intent parser detects a `record_expense` intent, a structured\ndraft transaction may be included in the response for review. A draft is\na preview only; posting happens through `POST /api/v1/expenses`, which is\nwhere an expense account and a payment account are chosen.\n\nBrowser callers authenticate with the session cookie and must include\n`csrf_token`; bearer clients are exempt from CSRF.\n\nScope: `write`. Operation: `chatBookkeeping`.",
                        "body": {
                            "mode": "raw",
                            "raw": "{\n    \"message\": \"How much did I spend on office supplies last month?\",\n    \"conversation\": [\n        {\n            \"role\": \"user\",\n            \"content\": \"What are my biggest expenses?\"\n        },\n        {\n            \"role\": \"assistant\",\n            \"content\": \"Your top expenses this month are...\"\n        }\n    ],\n    \"context\": {\n        \"page\": \"dashboard\"\n    }\n}",
                            "options": {
                                "raw": {
                                    "language": "json"
                                }
                            }
                        }
                    },
                    "response": []
                }
            ]
        }
    ]
}
