# API overview The DK SaaS customer portal is powered by a REST API implemented as Odoo HTTP controllers (module `dk_customer_portal_api`), consumed by the React frontend (`dk_customer_portal`, served at `portal.dishonkadoh.com`) and by the mobile app. ## Base URL Requests go to your Odoo instance's HTTP root, e.g.: ```text https://erp.dishonkadoh.com/api/... ``` For local development against `localhost:8069`, the same paths apply. ## Conventions **Every route is `type="http"`, not JSON-RPC** — send a plain `POST`/`GET` with a JSON body (not the `{"jsonrpc": "2.0", "params": {...}}` envelope Odoo's default web client uses), and read a plain JSON response back. **Response envelope.** Nearly every endpoint returns an object with a `success` boolean: ```json { "success": true, "...": "..." } ``` ```json { "success": false, "message": "Human-readable error" } ``` **Status codes** follow normal HTTP semantics: `200` success, `400` validation error, `401` missing/invalid bearer token, `404` resource not found (or not owned by the caller's tenant), `500` unhandled server error (with `message` set to `str(exception)` — controllers wrap their body in a broad `try/except` and log with `_logger.exception(...)`). **Authentication.** Almost all routes require `Authorization: Bearer ` obtained from `/api/login`. See [Authentication](../authentication.md) for the full flow. `/api/login`, `/api/register`, `/api/demo/register`, the OAuth start/callback routes, and `/api/plans` (public pricing) are the exceptions. **CORS.** Every controller answers `OPTIONS` preflight requests and only reflects `Access-Control-Allow-Origin` for an allow-listed set of origins. See [Authentication § CORS](../authentication.md) for the list. **Tenant scoping.** Once authenticated, most endpoints resolve the caller's `saas.tenant` via `partner_id` on the authenticated user, then scope every query to that tenant (`instances`, `invoices`, `backups`, `tickets`, etc. are all filtered by `tenant_id`). A valid token for a user with no tenant record returns `404 Tenant not found` rather than an empty list. ## Endpoint groups | Area | Routes | Reference | |---|---|---| | Auth & registration | `/api/login`, `/api/register`, `/api/demo/register`, `/api/auth/*` | [Authentication](../authentication.md) | | Plans & subscriptions | `/api/plans`, `/api/subscription/*` | [Subscriptions](subscriptions.md) | | Instances | `/api/instances*` | [Instances](instances.md) | | Instance modules & addon sources | `/api/modules`, `/api/instances//modules`, `/api/addon-sources*` | [Modules](modules.md) | | Dashboard, activity, settings, `/api/me` | `/api/dashboard`, `/api/activity`, `/api/settings*`, `/api/me` | [Dashboard](dashboard.md) | | Users & invitations | `/api/users*` | [Users](users.md) | | Billing & invoices | `/api/invoices*`, `/api/billing` | [Billing](billing.md) | | Backups | `/api/backups*` | [Backups](backups.md) | | Support tickets | `/api/tickets*` | [Tickets](tickets.md) | 75 routes exist across the module in total; the pages above cover every one grouped by resource. If you add a new controller file, add its routes to the matching page (or a new one, listed in `index.rst`) so this table stays accurate.