# OpenBusinessAPI (OBAPI) -- Full Specification > Machine-generated single-file concatenation of the OBAPI documentation, for ingestion by AI agents and tools. > Canonical site: https://obapi.org -- OpenAPI contract: https://obapi.org/assets/openapi.yaml --- # OpenBusinessAPI Source: https://obapi.org/ # OBAPI -- Open Business API **OBAPI** is an open standard that defines a unified REST API for exchanging business documents between companies. ## The problem Every month, businesses download invoices, orders and other documents from dozens of provider portals -- each with its own interface. Tools like web scrapers (woob.tech, cozy.io) try to solve this, but break every time a provider redesigns their website. ## The solution OBAPI reverses the problem **at the source**: providers expose a standard API endpoint. Any OBAPI-compatible client can retrieve documents from any OBAPI-compatible provider, without provider-specific code. Think of it as RSS for business documents. ``` GET /obapi/v1/invoices Authorization: Bearer {token} ``` One client, any provider. No scraping, no maintenance. ## Scope OBAPI covers **24 business objects** organized in 3 tiers: **Tier 1 -- Core** (9 objects): Thirdparty, Contact, Product, Proposal, Order, Invoice, Credit Note, Shipment, Download **Tier 2 -- Extended** (7 objects): Supplier Proposal, Supplier Order, Supplier Invoice, Reception, Contract, Intervention, Ticket **Tier 3 -- Advanced** (8 objects): Project, Task, Expense Report, BOM, Manufacturing Order, Warehouse, Member, Category Plus transversal concerns: Discovery, Authentication, Pagination, Error handling, Dictionaries. A server can implement any subset -- the [Discovery endpoint](/v1/discovery) tells clients which capabilities are available. ## Key design principles - **Read-only** (GET only) -- safe to expose, no risk of data corruption - **ERP-agnostic** -- works with Dolibarr, Odoo, SAP, custom systems, or any backend - **Simple** -- standard REST, JSON responses, Bearer token auth - **Predictable** -- consistent field naming, pagination, error format across all objects - **Progressive** -- implement Tier 1 first, add Tier 2 and 3 when needed ## Get started - Browse the [v1 specification](/v1) - Download the [OpenAPI spec (YAML)](/assets/openapi.yaml) - Check the [demonstration](/v1/demo) ## Join us - GitHub: [github.com/OpenBusinessAPI](https://github.com/OpenBusinessAPI) - License: MIT --- # For AI Agents Source: https://obapi.org/v1/for-ai-agents ## For AI Agents OBAPI is designed to be implemented with the help of an AI coding assistant. The whole specification is exposed as machine-readable, single-URL entry points so you can hand an agent one link and let it do the work. ### Entry points | URL | What it is | | --- | --- | | `https://obapi.org/llms.txt` | Curated map of the spec (markdown links), following the [llmstxt.org](https://llmstxt.org) convention. Best first read for an agent. | | `https://obapi.org/llms-full.txt` | Every documentation page concatenated into one file. One fetch, full context. | | `https://obapi.org/assets/openapi.yaml` | The OpenAPI 3 contract -- the machine-readable source of truth for endpoints and schemas. | ### Copy-paste prompt Paste this into your AI coding agent (Claude Code, Cursor, etc.), adjusting the last line to your project: ``` Read the OBAPI specification at https://obapi.org/llms-full.txt (and the OpenAPI contract at https://obapi.org/assets/openapi.yaml). OBAPI is an open standard REST API for exchanging business documents (invoices, orders, proposals, and more). Help me implement an OBAPI-compatible in my tool. Start by summarising the objects and endpoints I need, propose an implementation plan, then generate the code following the spec's conventions for authentication, discovery, pagination and error handling. ``` ### Tips - Ask the agent to begin with the **Discovery** and **Authentication** pages: they define how a client negotiates capabilities and authenticates before touching any business object. - OBAPI groups objects in tiers (Core, Extended, Advanced). Tell the agent which tier you need so it does not over-implement. - The OpenAPI file is authoritative for exact field names and types; the markdown pages give the intent and workflows behind them. --- # Workflows Source: https://obapi.org/v1/workflows ## Workflows & Relationships Understanding how OBAPI objects relate to each other and how documents flow through their lifecycle. ### Commercial document flow The core B2B exchange follows a predictable pipeline:
graph LR P[Proposal] -->|signed| O[Order] O -->|fulfilled| S[Shipment] O -->|billed| I[Invoice] I -->|correction| CN[Credit Note] I -->|PDF| D[Download] O -->|PDF| D P -->|PDF| D S -->|PDF| D CN -->|PDF| D
A typical flow: 1. **Proposal** (quotation) is created and sent to the customer 2. Customer **signs** the proposal -- status changes to `signed` 3. An **Order** is created from the proposal 4. Goods are shipped via a **Shipment** 5. An **Invoice** is generated for the order 6. If needed, a **Credit Note** corrects the invoice 7. Any document can be **Downloaded** as PDF Not every step is mandatory. An invoice can exist without a prior proposal. A shipment can exist without a formal order. ### Supplier-side mirror The purchasing flow mirrors the sales flow:
graph LR SP[Supplier Proposal] -->|accepted| SO[Supplier Order] SO -->|delivered| R[Reception] SO -->|billed| SI[Supplier Invoice]
### Invoice lifecycle
stateDiagram-v2 [*] --> draft draft --> validated : validate validated --> paid : payment received validated --> abandoned : write off paid --> [*] abandoned --> [*]
| Status | Meaning | |---|---| | `draft` | Invoice created, not yet finalized | | `validated` | Finalized, sent to customer, awaiting payment | | `paid` | Fully paid | | `abandoned` | Written off, no longer expected to be paid | ### Order lifecycle
stateDiagram-v2 [*] --> draft draft --> validated : validate validated --> in_progress : start processing in_progress --> delivered : all shipped validated --> cancelled : cancel in_progress --> cancelled : cancel delivered --> [*] cancelled --> [*]
### Proposal lifecycle
stateDiagram-v2 [*] --> draft draft --> validated : validate & send validated --> signed : customer accepts validated --> refused : customer declines signed --> billed : invoice created billed --> [*] refused --> [*]
### Supplier order lifecycle
stateDiagram-v2 [*] --> draft draft --> validated : validate validated --> approved : approve approved --> ordered : send to supplier ordered --> received_partially : partial delivery ordered --> received_completely : full delivery received_partially --> received_completely : remaining delivered validated --> cancelled : cancel approved --> refused : refuse received_completely --> [*] cancelled --> [*] refused --> [*]
### Shipment lifecycle
stateDiagram-v2 [*] --> draft draft --> validated : ship validated --> closed : delivered closed --> [*]
### Entity relationships
erDiagram THIRDPARTY ||--o{ CONTACT : "has" THIRDPARTY ||--o{ PROPOSAL : "receives" THIRDPARTY ||--o{ ORDER : "places" THIRDPARTY ||--o{ INVOICE : "is billed" PROPOSAL ||--o| ORDER : "becomes" ORDER ||--o{ SHIPMENT : "fulfilled by" ORDER ||--o{ INVOICE : "billed as" INVOICE ||--o{ CREDITNOTE : "corrected by" CONTRACT ||--o{ INTERVENTION : "serviced by" PROJECT ||--o{ TASK : "contains" BOM ||--o{ MANUFACTURING_ORDER : "produces"
### How to navigate between entities | From | To | How | |---|---|---| | Order | Shipments | List shipments, filter by `order_ref` matching the order's `ref` | | Order | Invoice | List invoices, the invoice may reference the order via its lines | | Proposal | Order | When a proposal is `signed`, the resulting order is created | | Invoice | Credit Note | A credit note has `related_invoice_ref` pointing to the original invoice | | Contract | Interventions | An intervention has `contract_ref` linking to the contract | | Project | Tasks | `GET /obapi/v1/projects/{id}` includes `tasks` array, or use `GET /obapi/v1/tasks?project_id={id}` | | Supplier Order | Reception | A reception has `origin_type: "supplier_order"` and `origin_id` linking to the order | | BOM | Manufacturing Order | A manufacturing order has `bom_ref` linking to the BOM | | Expense Report | Project | Each expense line may have a `project_ref` | ### Download any document The Download endpoint is a universal gateway to PDF files: ``` GET /obapi/v1/download/{id}?type={type} ``` Supported types: `invoice`, `creditnote`, `order`, `proposal`, `shipment`, `supplier-proposal`, `supplier-order`, `supplier-invoice`, `reception`, `contract`, `intervention`, `expense-report`. --- # Getting Started Source: https://obapi.org/v1/getting-started ## Getting Started Get your first OBAPI response in 5 minutes. ### Prerequisites - An OBAPI-compatible provider (e.g. a Dolibarr instance with the OBAPI module) - An API token (Bearer token) provided by your provider - A tool to make HTTP requests: `curl`, Postman, or any HTTP client ### Step 1 -- Check server capabilities The Discovery endpoint requires **no authentication** and tells you what the server supports: ``` GET https://provider.example.com/obapi/v1/discovery ``` ```json { "discovery": { "provider": "Acme Corp", "obapi_version": "1.0", "endpoints": [ "thirdparty", "contacts", "products", "proposals", "orders", "invoices", "creditnotes", "shipments", "download" ], "tier": 1, "authentication": ["bearer"], "documentation": "https://obapi.org" } } ``` This tells you the server implements **Tier 1** and accepts **Bearer token** authentication. ### Step 2 -- Authenticate All other endpoints require a Bearer token in the `Authorization` header: ``` Authorization: Bearer your-api-token-here ``` How you obtain the token depends on the provider (pre-shared key, OAuth2, login/password, etc.). Check with your provider. ### Step 3 -- Retrieve invoices Let's fetch the latest invoices: ``` GET https://provider.example.com/obapi/v1/invoices Authorization: Bearer your-api-token-here ``` Response: ```json { "items": [ { "id": "1042", "ref": "FA2405-0001", "customer_ref": "PO-2024-789", "date_invoice": "2024-05-15", "date_due": "2024-06-15", "status": "validated", "total_excl_tax": "1500.00", "total_vat": "300.00", "total_incl_tax": "1800.00" } ], "pagination": { "page": 1, "per_page": 50, "total_items": 1, "total_pages": 1 } } ``` ### Step 4 -- Get invoice details Fetch a single invoice with its line items: ``` GET https://provider.example.com/obapi/v1/invoices/1042 Authorization: Bearer your-api-token-here ``` The response includes all fields plus the `lines` array with each line item. ### Step 5 -- Download the PDF ``` GET https://provider.example.com/obapi/v1/download/1042?type=invoice Authorization: Bearer your-api-token-here ``` The server returns the binary PDF with `Content-Type: application/pdf`. ### Using pagination List endpoints accept `page` and `per_page` parameters: ``` GET /obapi/v1/invoices?page=2&per_page=20 ``` The response always includes a `pagination` object so you know how many pages remain. ### Filtering by date Most list endpoints accept `date_start` and `date_end`: ``` GET /obapi/v1/invoices?date_start=2024-01-01&date_end=2024-12-31 ``` ### Error handling If something goes wrong, OBAPI returns a structured error: ```json { "error": { "type": "authentication_error", "code": "INVALID_TOKEN", "message": "The provided Bearer token is invalid or expired" } } ``` Always check the HTTP status code first (401, 403, 404, 422, 500), then read the `error` object for details. See the full [error reference](/v1/errors). ### Next steps - Browse the [v1 specification](/v1) for all endpoints - Check the [workflow diagrams](/v1/workflows) to understand the document lifecycle - Explore the [interactive API reference](/v1/explorer) - Download the [OpenAPI spec](/assets/openapi.yaml) to generate client code --- # Draft v1 Source: https://obapi.org/v1 # OpenBusinessAPI -- draft version 1 Sources: [GitHub](https://github.com/OpenBusinessAPI) | [Specification](https://inligit.fr/obapi/doc) ## Base endpoint **`/obapi/v1`** ## Overview OBAPI objects are organized in three tiers: ### Tier 1 -- Core Essential B2B exchange. Covers 90% of business interoperability needs. | Endpoint | Description | |---|---| | `GET /obapi/v1` | Discovery -- server capabilities | | `GET /obapi/v1/thirdparty` | Provider identity | | `GET /obapi/v1/contacts` | Contact persons | | `GET /obapi/v1/products` | Product & service catalog | | `GET /obapi/v1/proposals` | Sales quotations | | `GET /obapi/v1/orders` | Customer orders | | `GET /obapi/v1/invoices` | Customer invoices | | `GET /obapi/v1/creditnotes` | Credit notes / avoirs | | `GET /obapi/v1/shipments` | Delivery / despatch advice | | `GET /obapi/v1/download/{id}` | Document download (PDF) | ### Tier 2 -- Extended Supplier-side flows and service management. | Endpoint | Description | |---|---| | `GET /obapi/v1/supplier-proposals` | Supplier proposals / RFQ | | `GET /obapi/v1/supplier-orders` | Purchase orders | | `GET /obapi/v1/supplier-invoices` | Supplier invoices received | | `GET /obapi/v1/receptions` | Goods receipt | | `GET /obapi/v1/contracts` | Service contracts / subscriptions | | `GET /obapi/v1/interventions` | Service intervention reports | | `GET /obapi/v1/tickets` | Support tickets | | `GET /obapi/v1/usage/metrics` | Usage metric catalog (self-describing) | | `GET /obapi/v1/usage` | Usage metrics values per account & period | ### Tier 3 -- Advanced Internal objects shareable between entities (consortiums, cooperatives, multi-site). | Endpoint | Description | |---|---| | `GET /obapi/v1/projects` | Project tracking | | `GET /obapi/v1/tasks` | Project tasks | | `GET /obapi/v1/expense-reports` | Expense claims | | `GET /obapi/v1/boms` | Bill of materials | | `GET /obapi/v1/manufacturing-orders` | Manufacturing orders | | `GET /obapi/v1/warehouses` | Stock locations | | `GET /obapi/v1/members` | Association members | | `GET /obapi/v1/categories` | Shared classification | ## Errors Conventional HTTP response codes: * **2xx** success * **4xx** client error (invalid parameters, authentication, not found) * **5xx** server error ### Error response format ```json { "error": { "type": "not_found", "code": "OBJECT_NOT_FOUND", "message": "Requested object does not exist" } } ``` ## Pagination All list endpoints return paginated results: ```json { "items": [ "..." ], "pagination": { "page": 1, "per_page": 50, "total_items": 234, "total_pages": 5 } } ``` Parameters: `page` (default: 1), `per_page` (default: 50, max: 200). ## Data types * **Dates**: ISO 8601 (`2024-05-23` or `2024-05-23T14:30:00Z`) * **Amounts**: strings with decimal point (`"1527.00"`, not floats) * **Currency**: ISO 4217 (`EUR`, `USD`) * **Booleans**: JSON `true` / `false` * **IDs**: always strings ## OpenAPI The full OpenAPI 3.1.0 specification is available on [GitHub](https://github.com/OpenBusinessAPI) for generating clients and interactive documentation. --- # Authentication Source: https://obapi.org/v1/auth ## Authentication Authentication is done via **Bearer token**. The enrollment process (how you obtain the token) is outside the scope of OBAPI -- each provider decides: login/password with JWT, pre-shared key, OAuth2, etc. The important thing is: your OBAPI server gives a token to the client. The client sends it with every request. ### Request header All authenticated requests must include: ``` Authorization: Bearer {YOUR_API_KEY} ``` ### Example ```bash curl -X GET \ -H "Authorization: Bearer abc123def456" \ https://provider.example.com/obapi/v1/invoices ``` ### Error responses **401 -- Invalid or missing token:** ```json { "error": { "type": "authentication_error", "code": "INVALID_TOKEN", "message": "Invalid or expired API token" } } ``` **403 -- Insufficient permissions:** ```json { "error": { "type": "authorization_error", "code": "INSUFFICIENT_PERMISSIONS", "message": "Your token does not have access to this resource" } } ``` --- # Discovery Source: https://obapi.org/v1/discovery ## Discovery The discovery endpoint lets a client know which objects and capabilities a given OBAPI server supports. Not every server will implement all tiers. This is the only endpoint that does **not** require authentication. * **Method**: `GET /obapi/v1` ### Response ```json { "obapi_version": "1.0", "provider": { "name": "My Company", "website": "https://example.com", "contact_email": "contact@example.com" }, "software": { "name": "Dolibarr", "version": "20.0.0" }, "capabilities": [ "thirdparty", "contacts", "products", "proposals", "orders", "invoices", "creditnotes", "shipments", "download" ], "pagination": { "default_per_page": 50, "max_per_page": 200 } } ``` ### Capabilities The `capabilities` array lists the object types this server supports. Clients should check this before calling endpoints. **Tier 1:** `thirdparty`, `contacts`, `products`, `proposals`, `orders`, `invoices`, `creditnotes`, `shipments`, `download` **Tier 2:** `supplier-proposals`, `supplier-orders`, `supplier-invoices`, `receptions`, `contracts`, `interventions`, `tickets`, `usage` **Tier 3:** `projects`, `tasks`, `expense-reports`, `boms`, `manufacturing-orders`, `warehouses`, `members`, `categories` A server that only supports invoices could return: ```json { "obapi_version": "1.0", "provider": { "name": "Minimal Provider" }, "capabilities": ["thirdparty", "invoices", "download"] } ``` A hosted service (mail, proxy, storage) that only reports usage metrics for billing is a valid minimal server too, even if it does not run Dolibarr: ```json { "obapi_version": "1.0", "provider": { "name": "Acme Hosting" }, "software": { "name": "custom", "version": "1.0" }, "capabilities": ["usage"] } ``` --- # Errors Source: https://obapi.org/v1/errors ## Error Handling OBAPI uses conventional HTTP response codes and a structured JSON error body. ### HTTP status codes | Code | Meaning | When | |---|---|---| | `200` | OK | Request succeeded | | `400` | Bad Request | Invalid parameters (e.g. malformed date, unknown filter value) | | `401` | Unauthorized | Missing or invalid Bearer token | | `403` | Forbidden | Token valid but insufficient permissions for this resource | | `404` | Not Found | Object does not exist or endpoint not implemented | | `405` | Method Not Allowed | Using POST/PUT/DELETE on a read-only API | | `422` | Unprocessable Entity | Parameters are syntactically valid but semantically wrong | | `429` | Too Many Requests | Rate limit exceeded (if provider implements rate limiting) | | `500` | Internal Server Error | Unexpected server-side failure | | `503` | Service Unavailable | Server temporarily down for maintenance | ### Error response format All errors return a JSON body with this structure: ```json { "error": { "type": "string -- error category", "code": "string -- machine-readable error code", "message": "string -- human-readable description" } } ``` ### Error types | Type | HTTP Code | Description | |---|---|---| | `authentication_error` | 401 | Token missing, invalid, or expired | | `authorization_error` | 403 | Token valid but access denied | | `not_found` | 404 | Resource does not exist | | `invalid_request` | 400, 422 | Request parameters are invalid | | `method_not_allowed` | 405 | HTTP method not supported | | `rate_limit` | 429 | Too many requests | | `server_error` | 500 | Internal failure | | `service_unavailable` | 503 | Temporary downtime | ### Error codes reference #### Authentication (401) | Code | Message | Cause | |---|---|---| | `MISSING_TOKEN` | Authorization header is required | No `Authorization: Bearer` header sent | | `INVALID_TOKEN` | The provided Bearer token is invalid or expired | Token does not match any active API key | | `EXPIRED_TOKEN` | The provided Bearer token has expired | Token was valid but is past its expiry | #### Authorization (403) | Code | Message | Cause | |---|---|---| | `INSUFFICIENT_PERMISSIONS` | Your token does not have access to this resource | API key exists but lacks the required scope | #### Not Found (404) | Code | Message | Cause | |---|---|---| | `OBJECT_NOT_FOUND` | Requested object does not exist | The `{id}` does not match any record | | `ENDPOINT_NOT_FOUND` | This endpoint is not available | Server does not implement this endpoint | | `DOCUMENT_NOT_FOUND` | No document available for this object | The object exists but has no downloadable file | #### Invalid Request (400, 422) | Code | Message | Cause | |---|---|---| | `INVALID_PARAMETER` | Parameter 'X' is invalid | A query parameter has an unexpected value | | `INVALID_DATE_FORMAT` | Date must be in YYYY-MM-DD format | A date parameter is malformed | | `INVALID_DATE_RANGE` | date_start must be before date_end | Date range is inverted | | `PAGE_OUT_OF_RANGE` | Page number exceeds available pages | Requested page > total_pages | | `PER_PAGE_TOO_LARGE` | per_page cannot exceed 200 | Requested more than 200 items per page | | `INVALID_STATUS_FILTER` | Unknown status value 'X' | Status filter does not match allowed values | #### Rate Limit (429) | Code | Message | Cause | |---|---|---| | `RATE_LIMIT_EXCEEDED` | Too many requests, retry after X seconds | Provider-defined rate limit hit | When a 429 is returned, the response includes a `Retry-After` header (in seconds). #### Server Errors (500, 503) | Code | Message | Cause | |---|---|---| | `INTERNAL_ERROR` | An unexpected error occurred | Bug or misconfiguration on the server | | `SERVICE_UNAVAILABLE` | Service temporarily unavailable | Planned maintenance or overload | ### Examples #### Missing authentication ``` GET /obapi/v1/invoices (no Authorization header) ``` ```json HTTP/1.1 401 Unauthorized { "error": { "type": "authentication_error", "code": "MISSING_TOKEN", "message": "Authorization header is required" } } ``` #### Object not found ``` GET /obapi/v1/invoices/99999 Authorization: Bearer valid-token ``` ```json HTTP/1.1 404 Not Found { "error": { "type": "not_found", "code": "OBJECT_NOT_FOUND", "message": "Requested object does not exist" } } ``` #### Invalid date range ``` GET /obapi/v1/invoices?date_start=2024-12-31&date_end=2024-01-01 Authorization: Bearer valid-token ``` ```json HTTP/1.1 422 Unprocessable Entity { "error": { "type": "invalid_request", "code": "INVALID_DATE_RANGE", "message": "date_start must be before date_end" } } ``` #### Empty results (not an error) A query that returns no matching items is **not** an error. It returns 200 with an empty array: ```json { "items": [], "pagination": { "page": 1, "per_page": 50, "total_items": 0, "total_pages": 0 } } ``` ### Best practices - **Always check the HTTP status code first** before parsing the body. - **Log the full error response** (`type`, `code`, `message`) for debugging. - **Handle 429 gracefully** by respecting the `Retry-After` header. - **Do not retry on 4xx errors** (except 429) -- the request is invalid and will fail again. - **Retry on 5xx errors** with exponential backoff (1s, 2s, 4s, max 3 retries). - **Use Discovery** to check which endpoints are available before calling them. --- # Thirdparty Source: https://obapi.org/v1/thirdparty ## Thirdparty The provider's identity. Unlike other objects, this endpoint is singular -- it returns who owns this OBAPI server. * **Method**: `GET /obapi/v1/thirdparty` * **Headers**: `Authorization: Bearer {apikey}` ### Response ```json { "thirdparty": { "id": "42", "name": "CAP-REL", "address": "123 rue Example", "zip": "30380", "city": "Saint Christol Les Ales", "state": "Gard", "country": "FR", "phone": "+33698744401", "email": "contact@cap-rel.fr", "website": "https://cap-rel.fr", "logo": "data:image/png;base64,...", "vat_number": "FR12345678901", "siret": "844 431 239 00012", "siren": "844431239", "ape_code": "6202A", "rcs": "NIMES", "capital": "1000.00", "legal_form": "SAS", "currency_code": "EUR", "language": "fr_FR", "public_note": "" } } ``` ### Notes `vat_number` is international. Fields `siret`, `siren`, `ape_code`, `rcs` are France-specific. Non-French providers leave them empty. --- # Contacts Source: https://obapi.org/v1/contacts ## Contacts Contact persons associated with the provider. ### List contacts * **Method**: `GET /obapi/v1/contacts` * **Headers**: `Authorization: Bearer {apikey}` | Parameter | Type | Required | Description | |---|---|---|---| | `page` | integer | no | Page number (default: 1) | | `per_page` | integer | no | Items per page (default: 50, max: 200) | ### Get a single contact * **Method**: `GET /obapi/v1/contacts/{id}` ### Response ```json { "items": [ { "id": "15", "civility": "MR", "lastname": "Dupont", "firstname": "Jean", "address": "10 rue de la Paix", "zip": "75002", "city": "Paris", "state": "Ile-de-France", "country": "FR", "phone": "+33140000000", "mobile": "+33612345678", "email": "jean.dupont@example.com", "public_note": "" } ], "pagination": { "page": 1, "per_page": 50, "total_items": 12, "total_pages": 1 } } ``` --- # Products Source: https://obapi.org/v1/products ## Products Product and service catalog. ### List products * **Method**: `GET /obapi/v1/products` * **Headers**: `Authorization: Bearer {apikey}` | Parameter | Type | Required | Description | |---|---|---|---| | `page` | integer | no | Page number (default: 1) | | `per_page` | integer | no | Items per page (default: 50, max: 200) | | `type` | string | no | `product` or `service` | | `for_sale` | boolean | no | Filter products for sale | | `for_purchase` | boolean | no | Filter products for purchase | | `search` | string | no | Search in ref, label, description | ### Get a single product * **Method**: `GET /obapi/v1/products/{id}` ### Response (single) ```json { "product": { "id": "101", "ref": "CONSULTING-01", "label": "Consulting service", "description": "Hourly consulting service", "type": "service", "price_excl_tax": "100.00", "price_incl_tax": "120.00", "price_min_excl_tax": "80.00", "price_min_incl_tax": "96.00", "price_base_type": "HT", "vat_rate": "20.000", "barcode": "", "weight": "", "weight_unit": "", "length": "", "width": "", "height": "", "stock": "", "stock_alert_threshold": "", "for_sale": true, "for_purchase": false, "created_at": "2023-01-15T10:30:00Z", "public_note": "" } } ``` ### Response (list) ```json { "items": [ { "id": "101", "ref": "CONSULTING-01", "label": "Consulting service", "type": "service", "price_excl_tax": "100.00", "price_incl_tax": "120.00", "for_sale": true, "for_purchase": false } ], "pagination": { "..." } } ``` --- # Proposals Source: https://obapi.org/v1/proposals ## Proposals Sales quotation / devis. ### List proposals * **Method**: `GET /obapi/v1/proposals` * **Headers**: `Authorization: Bearer {apikey}` | Parameter | Type | Required | Description | |---|---|---|---| | `page` | integer | no | Page number (default: 1) | | `per_page` | integer | no | Items per page (default: 50, max: 200) | | `date_start` | string | no | From date (YYYY-MM-DD) | | `date_end` | string | no | To date (YYYY-MM-DD) | | `status` | string | no | `draft`, `validated`, `signed`, `refused`, `billed` | | `sort` | string | no | `date_asc`, `date_desc` (default), `ref_asc`, `ref_desc` | ### Get a single proposal * **Method**: `GET /obapi/v1/proposals/{id}` ### Status values | Value | Description | |---|---| | `draft` | Draft proposal | | `validated` | Sent to customer | | `signed` | Accepted by customer | | `refused` | Refused by customer | | `billed` | Invoice created | ### Response (single) ```json { "proposal": { "id": "205", "ref": "PR2405-0012", "customer_ref": "Your ref 123", "date_proposal": "2024-05-10", "date_expiry": "2024-06-10", "date_delivery": "2024-07-01", "signed_at": null, "validated_at": "2024-05-10T14:00:00Z", "created_at": "2024-05-09T09:30:00Z", "updated_at": "2024-05-10T14:00:00Z", "status": "validated", "payment_terms": "Net 30 days", "payment_method": "Bank transfer", "total_excl_tax": "5000.00", "total_vat": "1000.00", "total_incl_tax": "6000.00", "multicurrency_code": "EUR", "public_note": "", "lines": [ { "id": "410", "position": 1, "product_ref": "CONSULTING-01", "product_label": "Consulting service", "product_type": "service", "description": "Technical consulting - May 2024", "quantity": "50.00", "unit": "hour", "unit_price_excl_tax": "100.00", "discount_percent": "0.00", "vat_rate": "20.000", "total_excl_tax": "5000.00", "total_vat": "1000.00", "total_incl_tax": "6000.00", "date_start": "2024-05-01", "date_end": "2024-05-31" } ] } } ``` ### Download PDF `GET /obapi/v1/download/{id}?type=proposal` --- # Orders Source: https://obapi.org/v1/orders ## Orders Customer orders. ### List orders * **Method**: `GET /obapi/v1/orders` * **Headers**: `Authorization: Bearer {apikey}` | Parameter | Type | Required | Description | |---|---|---|---| | `page` | integer | no | Page number (default: 1) | | `per_page` | integer | no | Items per page (default: 50, max: 200) | | `date_start` | string | no | From date (YYYY-MM-DD) | | `date_end` | string | no | To date (YYYY-MM-DD) | | `status` | string | no | `draft`, `validated`, `in_progress`, `delivered`, `cancelled` | | `sort` | string | no | `date_asc`, `date_desc` (default), `ref_asc`, `ref_desc` | ### Get a single order * **Method**: `GET /obapi/v1/orders/{id}` ### Status values | Value | Description | |---|---| | `draft` | Draft order | | `validated` | Validated | | `in_progress` | Being processed / shipped | | `delivered` | Fully delivered | | `cancelled` | Cancelled | ### Response (list) ```json { "items": [ { "id": "350", "ref": "CO2405-0018", "customer_ref": "PO-2024-042", "date_order": "2024-05-15", "status": "validated", "is_billed": false, "total_excl_tax": "5000.00", "total_vat": "1000.00", "total_incl_tax": "6000.00" } ], "pagination": { "page": 1, "per_page": 50, "total_items": 3, "total_pages": 1 } } ``` ### Response (single) ```json { "order": { "id": "350", "ref": "CO2405-0018", "customer_ref": "PO-2024-042", "date_order": "2024-05-15", "date_delivery": "2024-06-01", "validated_at": "2024-05-15T10:00:00Z", "created_at": "2024-05-14T16:00:00Z", "updated_at": "2024-05-15T10:00:00Z", "status": "validated", "is_billed": false, "payment_terms": "Net 30 days", "payment_method": "Bank transfer", "shipping_method": "Colissimo", "total_excl_tax": "5000.00", "total_vat": "1000.00", "total_incl_tax": "6000.00", "public_note": "", "lines": [ { "id": "720", "position": 1, "product_ref": "CONSULTING-01", "product_label": "Consulting service", "product_type": "service", "description": "Technical consulting", "quantity": "50.00", "unit": "hour", "unit_price_excl_tax": "100.00", "discount_percent": "0.00", "vat_rate": "20.000", "total_excl_tax": "5000.00", "total_vat": "1000.00", "total_incl_tax": "6000.00" } ] } } ``` ### Download PDF `GET /obapi/v1/download/{id}?type=order` --- # Invoices Source: https://obapi.org/v1/invoices ## Invoices Customer invoices. This is the original and primary OBAPI use case. ### List invoices * **Method**: `GET /obapi/v1/invoices` * **Headers**: `Authorization: Bearer {apikey}` | Parameter | Type | Required | Description | |---|---|---|---| | `page` | integer | no | Page number (default: 1) | | `per_page` | integer | no | Items per page (default: 50, max: 200) | | `date_start` | string | no | From invoice date (YYYY-MM-DD) | | `date_end` | string | no | To invoice date (YYYY-MM-DD) | | `status` | string | no | `draft`, `validated`, `paid`, `abandoned` | | `sort` | string | no | `date_asc`, `date_desc` (default), `ref_asc`, `ref_desc` | ### Get a single invoice * **Method**: `GET /obapi/v1/invoices/{id}` ### Status values | Value | Description | |---|---| | `draft` | Draft invoice | | `validated` | Validated, not yet paid | | `paid` | Fully paid | | `abandoned` | Abandoned / written off | ### Response (list) ```json { "items": [ { "id": "850", "ref": "FA2209-0646", "customer_ref": "", "date_invoice": "2022-09-09", "date_due": "2022-10-09", "status": "paid", "total_excl_tax": "1527.00", "total_vat": "305.40", "total_incl_tax": "1832.40", "amount_paid": "1832.40", "remaining": "0.00" }, { "id": "1081", "ref": "FA2212-0842", "customer_ref": "", "date_invoice": "2022-12-06", "date_due": "2023-01-05", "status": "paid", "total_excl_tax": "1527.00", "total_vat": "305.40", "total_incl_tax": "1832.40", "amount_paid": "1832.40", "remaining": "0.00" } ], "pagination": { "page": 1, "per_page": 50, "total_items": 2, "total_pages": 1 } } ``` ### Response (single) ```json { "invoice": { "id": "2800", "ref": "FA2405-2401", "customer_ref": "Abonnement The/Cafe", "type": "standard", "date_invoice": "2024-05-24", "date_due": "2024-05-25", "validated_at": "2024-05-24T10:00:00Z", "created_at": "2024-05-24T09:00:00Z", "updated_at": "2024-05-24T10:00:00Z", "status": "paid", "payment_terms": "Due upon receipt", "payment_method": "Bank transfer", "total_excl_tax": "1.00", "total_vat": "0.20", "total_incl_tax": "1.20", "amount_paid": "1.20", "remaining": "0.00", "multicurrency_code": "EUR", "public_note": "", "payments": [ { "date": "2024-05-25", "amount": "1.20", "method": "Bank transfer", "reference": "VIRT-20240525-001" } ], "lines": [ { "id": "5430", "position": 1, "product_ref": "BUYMEACOFFEE", "product_label": "Buy me a coffee", "product_type": "service", "description": "Buy me a coffee", "quantity": "1.00", "unit": "piece", "unit_price_excl_tax": "0.50", "discount_percent": "0.00", "vat_rate": "20.000", "total_excl_tax": "0.50", "total_vat": "0.10", "total_incl_tax": "0.60" }, { "id": "5431", "position": 2, "product_ref": "BUYMEATEA", "product_label": "Buy me a tea", "product_type": "service", "description": "Buy me a tea", "quantity": "1.00", "unit": "piece", "unit_price_excl_tax": "0.50", "discount_percent": "0.00", "vat_rate": "20.000", "total_excl_tax": "0.50", "total_vat": "0.10", "total_incl_tax": "0.60" } ], "customer": { "id": "100", "name": "Client Example", "address": "10 rue du Client", "zip": "75001", "city": "Paris", "country": "FR", "email": "client@example.com" }, "supplier": { "id": "0", "name": "CAP-REL", "address": "123 rue du Fournisseur", "zip": "30380", "city": "Saint Christol Les Ales", "country": "FR", "email": "contact@cap-rel.fr", "phone": "+33698744401" } } } ``` ### Download PDF `GET /obapi/v1/download/{id}?type=invoice` --- # Credit Notes Source: https://obapi.org/v1/creditnotes ## Credit Notes Credit note / avoir. Same structure as Invoice with `type` always set to `credit_note`. ### List credit notes * **Method**: `GET /obapi/v1/creditnotes` * **Headers**: `Authorization: Bearer {apikey}` Parameters: same as Invoices (`page`, `per_page`, `date_start`, `date_end`, `status`, `sort`). ### Get a single credit note * **Method**: `GET /obapi/v1/creditnotes/{id}` ### Status values Same as Invoices: `draft`, `validated`, `paid`, `abandoned`. ### Response (single) ```json { "creditnote": { "id": "3050", "ref": "AV2405-0001", "customer_ref": "", "type": "credit_note", "related_invoice_ref": "FA2405-2401", "date_invoice": "2024-05-28", "date_due": "2024-05-28", "status": "validated", "total_excl_tax": "1.00", "total_vat": "0.20", "total_incl_tax": "1.20", "public_note": "Refund for invoice FA2405-2401", "lines": [ { "id": "5500", "position": 1, "product_ref": "BUYMEACOFFEE", "product_label": "Buy me a coffee", "product_type": "service", "description": "Refund", "quantity": "1.00", "unit_price_excl_tax": "1.00", "vat_rate": "20.000", "total_excl_tax": "1.00", "total_vat": "0.20", "total_incl_tax": "1.20" } ] } } ``` ### Notes All amounts are positive -- the sign is implied by the document type (credit note = negative in accounting). ### Download PDF `GET /obapi/v1/download/{id}?type=creditnote` --- # Shipments Source: https://obapi.org/v1/shipments ## Shipments Delivery / despatch advice. Represents goods shipped to the customer. ### List shipments * **Method**: `GET /obapi/v1/shipments` * **Headers**: `Authorization: Bearer {apikey}` | Parameter | Type | Required | Description | |---|---|---|---| | `page` | integer | no | Page number (default: 1) | | `per_page` | integer | no | Items per page (default: 50, max: 200) | | `date_start` | string | no | From date (YYYY-MM-DD) | | `date_end` | string | no | To date (YYYY-MM-DD) | | `status` | string | no | `draft`, `validated`, `closed` | | `sort` | string | no | `date_asc`, `date_desc` (default), `ref_asc`, `ref_desc` | ### Get a single shipment * **Method**: `GET /obapi/v1/shipments/{id}` ### Response (single) ```json { "shipment": { "id": "42", "ref": "EX2405-0003", "customer_ref": "", "date_shipment": "2024-05-20", "date_delivery": "2024-05-22", "validated_at": "2024-05-20T08:00:00Z", "created_at": "2024-05-19T16:00:00Z", "updated_at": "2024-05-20T08:00:00Z", "status": "validated", "order_ref": "CO2405-0018", "tracking_number": "6A12345678", "tracking_url": "https://tracking.example.com/6A12345678", "shipping_method": "Colissimo", "weight": "2.500", "weight_units": "kg", "billed": false, "public_note": "", "lines": [ { "id": "85", "product_ref": "WIDGET-01", "product_label": "Widget standard", "quantity": "10.00", "warehouse": "Main warehouse", "position": 1 } ] } } ``` ### Download PDF `GET /obapi/v1/download/{id}?type=shipment` --- # Download Source: https://obapi.org/v1/download ## Download Generic document download. Returns the binary PDF for any OBAPI object. * **Method**: `GET /obapi/v1/download/{id}` * **Headers**: `Authorization: Bearer {apikey}` ### Parameters | Parameter | Type | Required | Description | |---|---|---|---| | `id` | string | yes | Object identifier | | `type` | string | yes | Object type (see below) | | `format` | string | no | Output format (default: `pdf`) | ### Supported types | Type | Description | |---|---| | `invoice` | Customer invoice | | `creditnote` | Credit note | | `order` | Customer order | | `proposal` | Sales proposal | | `shipment` | Delivery slip | | `supplier-invoice` | Supplier invoice | | `supplier-order` | Purchase order | | `supplier-proposal` | Supplier proposal | | `reception` | Goods receipt | | `contract` | Service contract | | `intervention` | Intervention report | | `expense-report` | Expense report | ### Response * **Content-Type**: `application/pdf` * **Content-Disposition**: `attachment; filename="FA2405-2401.pdf"` * **Body**: binary file content ### Example ```bash curl -X GET \ -H "Authorization: Bearer abc123" \ -o FA2405-2401.pdf \ "https://provider.example.com/obapi/v1/download/2800?type=invoice" ``` ### Error ```json { "error": { "type": "not_found", "code": "DOCUMENT_NOT_FOUND", "message": "No document available for this object" } } ``` --- # Supplier Proposals Source: https://obapi.org/v1/supplier-proposals ## Supplier Proposals Request for quotation / price request sent to a supplier. ### Endpoints * `GET /obapi/v1/supplier-proposals` -- list * `GET /obapi/v1/supplier-proposals/{id}` -- single with lines * `GET /obapi/v1/download/{id}?type=supplier-proposal` -- PDF ### Parameters `page`, `per_page`, `date_start`, `date_end`, `status`, `sort` ### Status values `draft`, `validated`, `signed`, `refused`, `closed` ### Response (list) ```json { "items": [ { "id": "80", "ref": "PF2405-0001", "supplier_ref": "Q-2024-112", "date_proposal": "2024-05-10", "status": "validated", "total_excl_tax": "2500.00", "total_vat": "500.00", "total_incl_tax": "3000.00" } ], "pagination": { "..." } } ``` ### Response (single) ```json { "supplier_proposal": { "id": "80", "ref": "PF2405-0001", "supplier_ref": "Q-2024-112", "date_proposal": "2024-05-10", "date_delivery": "2024-06-15", "validated_at": "2024-05-11T09:00:00Z", "created_at": "2024-05-10T14:00:00Z", "updated_at": "2024-05-11T09:00:00Z", "status": "validated", "payment_terms": "Net 30 days", "payment_method": "Bank transfer", "total_excl_tax": "2500.00", "total_vat": "500.00", "total_incl_tax": "3000.00", "multicurrency_code": "EUR", "multicurrency_total_excl_tax": "2500.00", "multicurrency_total_vat": "500.00", "multicurrency_total_incl_tax": "3000.00", "public_note": "", "lines": [ { "id": "160", "position": 1, "product_ref": "COMP-A1", "product_label": "Component A1", "product_type": "product", "description": "Main circuit board", "quantity": "100.00", "unit": "piece", "unit_price_excl_tax": "25.00", "discount_percent": "0.00", "vat_rate": "20.000", "total_excl_tax": "2500.00", "total_vat": "500.00", "total_incl_tax": "3000.00", "multicurrency_code": "EUR", "multicurrency_unit_price": "25.00", "multicurrency_total_excl_tax": "2500.00", "multicurrency_total_vat": "500.00", "multicurrency_total_incl_tax": "3000.00" } ] } } ``` ### Download PDF `GET /obapi/v1/download/{id}?type=supplier-proposal` --- # Supplier Orders Source: https://obapi.org/v1/supplier-orders ## Supplier Orders Purchase orders sent to suppliers. ### Endpoints * `GET /obapi/v1/supplier-orders` -- list * `GET /obapi/v1/supplier-orders/{id}` -- single with lines * `GET /obapi/v1/download/{id}?type=supplier-order` -- PDF ### Parameters `page`, `per_page`, `date_start`, `date_end`, `status`, `sort` ### Status values | Value | Description | |---|---| | `draft` | Draft | | `validated` | Validated | | `approved` | Approved | | `ordered` | Sent to supplier | | `received_partially` | Partially received | | `received_completely` | Fully received | | `cancelled` | Cancelled | | `refused` | Refused | ### Response (list) ```json { "items": [ { "id": "120", "ref": "CF2405-0003", "supplier_ref": "SO-2024-789", "date_order": "2024-05-12", "date_delivery": "2024-06-01", "status": "ordered", "billed": false, "total_excl_tax": "3200.00", "total_vat": "640.00", "total_incl_tax": "3840.00" } ], "pagination": { "..." } } ``` ### Response (single) ```json { "supplier_order": { "id": "120", "ref": "CF2405-0003", "supplier_ref": "SO-2024-789", "date_order": "2024-05-12", "date_order_supplier": "2024-05-14", "date_delivery": "2024-06-01", "validated_at": "2024-05-12T10:00:00Z", "approved_at": "2024-05-13T09:30:00Z", "created_at": "2024-05-12T09:00:00Z", "updated_at": "2024-05-14T11:00:00Z", "status": "ordered", "billed": false, "payment_terms": "Net 30 days", "payment_method": "Bank transfer", "bank_account": "Main account", "total_excl_tax": "3200.00", "total_vat": "640.00", "total_incl_tax": "3840.00", "multicurrency_code": "EUR", "multicurrency_total_excl_tax": "3200.00", "multicurrency_total_vat": "640.00", "multicurrency_total_incl_tax": "3840.00", "public_note": "", "lines": [ { "id": "240", "position": 1, "product_ref": "COMP-A1", "product_label": "Component A1", "product_type": "product", "description": "Main circuit board", "quantity": "200.00", "unit": "piece", "unit_price_excl_tax": "16.00", "discount_percent": "0.00", "vat_rate": "20.000", "total_excl_tax": "3200.00", "total_vat": "640.00", "total_incl_tax": "3840.00", "multicurrency_code": "EUR", "multicurrency_unit_price": "16.00", "multicurrency_total_excl_tax": "3200.00", "multicurrency_total_vat": "640.00", "multicurrency_total_incl_tax": "3840.00" } ] } } ``` ### Download PDF `GET /obapi/v1/download/{id}?type=supplier-order` --- # Supplier Invoices Source: https://obapi.org/v1/supplier-invoices ## Supplier Invoices Invoices received from suppliers. ### Endpoints * `GET /obapi/v1/supplier-invoices` -- list * `GET /obapi/v1/supplier-invoices/{id}` -- single with lines * `GET /obapi/v1/download/{id}?type=supplier-invoice` -- PDF ### Parameters `page`, `per_page`, `date_start`, `date_end`, `status`, `sort` ### Status values | Value | Description | |---|---| | `draft` | Draft | | `validated` | Validated, not yet paid | | `paid` | Fully paid | | `abandoned` | Abandoned | ### Response (list) ```json { "items": [ { "id": "450", "ref": "FI2405-0012", "supplier_ref": "INV-2024-5678", "label": "May 2024 services", "date_invoice": "2024-05-20", "date_due": "2024-06-20", "status": "validated", "paid": false, "total_excl_tax": "4200.00", "total_vat": "840.00", "total_incl_tax": "5040.00", "amount_paid": "0.00", "remaining": "5040.00" } ], "pagination": { "..." } } ``` ### Response (single) ```json { "supplier_invoice": { "id": "450", "ref": "FI2405-0012", "supplier_ref": "INV-2024-5678", "label": "May 2024 services", "type": "standard", "date_invoice": "2024-05-20", "date_due": "2024-06-20", "validated_at": "2024-05-21T09:00:00Z", "created_at": "2024-05-20T14:30:00Z", "updated_at": "2024-05-21T09:00:00Z", "status": "validated", "paid": false, "payment_terms": "Net 30 days", "payment_method": "Bank transfer", "bank_account": "Main account", "total_excl_tax": "4200.00", "total_vat": "840.00", "total_incl_tax": "5040.00", "amount_paid": "0.00", "remaining": "5040.00", "multicurrency_code": "EUR", "close_code": "", "close_note": "", "public_note": "", "payments": [], "lines": [ { "id": "890", "position": 1, "product_ref": "HOSTING-PRO", "product_label": "Professional hosting", "product_type": "service", "description": "Hosting May 2024", "quantity": "1.00", "unit": "month", "unit_price_excl_tax": "4200.00", "discount_percent": "0.00", "vat_rate": "20.000", "total_excl_tax": "4200.00", "total_vat": "840.00", "total_incl_tax": "5040.00" } ] } } ``` ### Invoice types | Value | Description | |---|---| | `standard` | Standard invoice | | `credit_note` | Credit note from supplier | | `deposit` | Deposit / down payment | ### Download PDF `GET /obapi/v1/download/{id}?type=supplier-invoice` --- # Receptions Source: https://obapi.org/v1/receptions ## Receptions Goods received from a supplier (receipt advice). The counterpart of shipments on the purchasing side. ### Endpoints * `GET /obapi/v1/receptions` -- list * `GET /obapi/v1/receptions/{id}` -- single with lines * `GET /obapi/v1/download/{id}?type=reception` -- PDF ### Parameters `page`, `per_page`, `date_start`, `date_end`, `status`, `sort` ### Status values | Value | Description | |---|---| | `draft` | Draft reception | | `validated` | Validated / received | | `closed` | Closed | ### Response (list) ```json { "items": [ { "id": "95", "ref": "REC2405-0004", "supplier_ref": "SHIP-2024-321", "date_reception": "2024-05-25", "status": "validated", "tracking_number": "1Z999AA10123456784", "billed": false } ], "pagination": { "..." } } ``` ### Response (single) ```json { "reception": { "id": "95", "ref": "REC2405-0004", "supplier_ref": "SHIP-2024-321", "date_reception": "2024-05-25", "date_delivery": "2024-05-24", "validated_at": "2024-05-25T08:30:00Z", "created_at": "2024-05-24T16:00:00Z", "updated_at": "2024-05-25T08:30:00Z", "status": "validated", "billed": false, "origin_type": "supplier_order", "origin_id": "120", "tracking_number": "1Z999AA10123456784", "tracking_url": "https://tracking.example.com/1Z999AA10123456784", "shipping_method": "UPS Standard", "weight": "12.50", "weight_units": "kg", "public_note": "", "lines": [ { "id": "210", "position": 1, "product_ref": "COMP-A1", "product_label": "Component A1", "quantity": "100.00", "warehouse": "Main warehouse", "comment": "" }, { "id": "211", "position": 2, "product_ref": "COMP-B2", "product_label": "Component B2", "quantity": "50.00", "warehouse": "Main warehouse", "comment": "Partial delivery, 50 remaining" } ] } } ``` ### Download PDF `GET /obapi/v1/download/{id}?type=reception` --- # Contracts Source: https://obapi.org/v1/contracts ## Contracts Service contracts and subscription agreements. ### Endpoints * `GET /obapi/v1/contracts` -- list * `GET /obapi/v1/contracts/{id}` -- single with lines * `GET /obapi/v1/download/{id}?type=contract` -- PDF ### Parameters `page`, `per_page`, `status`, `sort` ### Status values | Value | Description | |---|---| | `draft` | Draft contract | | `validated` | Active / validated | | `closed` | Closed / terminated | ### Response (list) ```json { "items": [ { "id": "30", "ref": "CT2405-0002", "customer_ref": "SLA-2024-01", "date_contract": "2024-01-01", "status": "validated" } ], "pagination": { "..." } } ``` ### Response (single) ```json { "contract": { "id": "30", "ref": "CT2405-0002", "customer_ref": "SLA-2024-01", "supplier_ref": "", "date_contract": "2024-01-01", "created_at": "2023-12-15T10:00:00Z", "updated_at": "2024-01-01T09:00:00Z", "status": "validated", "public_note": "", "lines": [ { "id": "55", "position": 1, "product_ref": "MAINT-GOLD", "product_label": "Gold maintenance plan", "description": "Annual maintenance contract", "quantity": "12.00", "unit_price_excl_tax": "500.00", "vat_rate": "20.000", "total_excl_tax": "6000.00", "total_vat": "1200.00", "total_incl_tax": "7200.00", "date_start_planned": "2024-01-01", "date_start_real": "2024-01-01", "date_end_planned": "2024-12-31", "date_end_real": null, "status": "active" } ] } } ``` ### Contract line statuses | Value | Description | |---|---| | `inactive` | Service not yet started | | `active` | Service running | | `closed` | Service ended | ### Download PDF `GET /obapi/v1/download/{id}?type=contract` --- # Interventions Source: https://obapi.org/v1/interventions ## Interventions Service intervention reports. Records on-site or remote work performed for a customer. ### Endpoints * `GET /obapi/v1/interventions` -- list * `GET /obapi/v1/interventions/{id}` -- single with lines * `GET /obapi/v1/download/{id}?type=intervention` -- PDF ### Parameters `page`, `per_page`, `date_start`, `date_end`, `status`, `sort` ### Status values | Value | Description | |---|---| | `draft` | Draft | | `validated` | Validated | | `done` | Completed | | `billed` | Billed | ### Response (list) ```json { "items": [ { "id": "42", "ref": "FI2405-0005", "date_intervention": "2024-05-18", "duration": 7200, "status": "done" } ], "pagination": { "..." } } ``` ### Response (single) ```json { "intervention": { "id": "42", "ref": "FI2405-0005", "customer_ref": "", "date_intervention": "2024-05-18", "date_start": "2024-05-18", "date_end": "2024-05-18", "contract_ref": "CT2405-0002", "description": "On-site server maintenance", "duration": 7200, "validated_at": "2024-05-19T09:00:00Z", "created_at": "2024-05-17T14:00:00Z", "updated_at": "2024-05-19T09:00:00Z", "status": "done", "public_note": "", "lines": [ { "id": "85", "position": 1, "description": "Hardware diagnostic and repair", "date": "2024-05-18", "duration": 3600, "product_ref": "SRV-MAINT" }, { "id": "86", "position": 2, "description": "Software update and configuration", "date": "2024-05-18", "duration": 3600, "product_ref": "SRV-CONF" } ] } } ``` ### Notes - `duration` is expressed in **seconds** (7200 = 2 hours). - Each line represents a task performed during the intervention. - `contract_ref` links the intervention to a service contract (if applicable). ### Download PDF `GET /obapi/v1/download/{id}?type=intervention` --- # Tickets Source: https://obapi.org/v1/tickets ## Tickets Support tickets for customer service and helpdesk. ### Endpoints * `GET /obapi/v1/tickets` -- list * `GET /obapi/v1/tickets/{id}` -- single ### Parameters `page`, `per_page`, `status`, `severity`, `sort` ### Status values | Value | Description | |---|---| | `new` | New ticket, not read | | `read` | Read by support | | `assigned` | Assigned to someone | | `in_progress` | Being worked on | | `waiting` | Waiting for customer response | | `resolved` | Resolved | | `closed` | Closed | | `cancelled` | Cancelled | ### Response (list) ```json { "items": [ { "id": "310", "ref": "TK2405-0021", "track_id": "abc123xyz", "subject": "Cannot access invoice PDF", "type_label": "Issue", "severity_label": "Medium", "status": "in_progress", "created_at": "2024-05-20T11:00:00Z", "updated_at": "2024-05-21T09:30:00Z" } ], "pagination": { "..." } } ``` ### Response (single) ```json { "ticket": { "id": "310", "ref": "TK2405-0021", "track_id": "abc123xyz", "subject": "Cannot access invoice PDF", "message": "When I try to download invoice FA2405-0012, I get a 404 error. The invoice appears in the list but the PDF link does not work.", "type_code": "ISSUE", "type_label": "Issue", "category_code": "BILLING", "category_label": "Billing", "severity_code": "MEDIUM", "severity_label": "Medium", "resolution": "", "progress": 50, "origin_email": "customer@example.com", "created_at": "2024-05-20T11:00:00Z", "updated_at": "2024-05-21T09:30:00Z", "read_at": "2024-05-20T11:15:00Z", "closed_at": null, "last_message_at": "2024-05-21T09:30:00Z", "status": "in_progress", "public_note": "" } } ``` ### Notes - `track_id` is a public identifier that can be shared with the customer for tracking. - `progress` is a percentage from 0 to 100. - Tickets have no PDF download endpoint. --- # Usage & Metering Source: https://obapi.org/v1/usage ## Usage & Metering Usage-based billing metrics for hosted services. This capability lets a central billing system (typically the OBAPI client) pull consumption metrics from any hosted service (mail hosting, proxy, storage, Nextcloud, etc.) in a normalized way, without knowing the service internals. The design is **self-describing** in two steps: 1. The server declares **which** metrics it exposes (`GET /obapi/v1/usage/metrics`). 2. The client asks for **the values** of those metrics for one account over a period (`GET /obapi/v1/usage`). A service that only implements this capability is a valid minimal OBAPI server: its discovery response lists `["usage"]` and nothing else. ### Metric catalog * **Method**: `GET /obapi/v1/usage/metrics` * **Headers**: `Authorization: Bearer {apikey}` Returns the list of metrics this server can measure. This endpoint takes no account parameter: it describes the service, not a specific customer. ```json { "metrics": [ { "code": "storage_bytes", "label": "Storage used", "description": "Total disk space occupied by the account", "unit": "byte", "kind": "gauge", "aggregation": "last", "billable": true, "product_ref": "NC-STORAGE" }, { "code": "user_count", "label": "Number of users", "unit": "count", "kind": "gauge", "aggregation": "max", "billable": true, "product_ref": "NC-USER" }, { "code": "bandwidth_bytes", "label": "Bandwidth consumed", "unit": "byte", "kind": "counter", "aggregation": "sum", "billable": true, "product_ref": "PROXY-TRAFFIC" } ] } ``` ### Metric object | Field | Type | Description | |---|---|---| | `code` | string | Stable machine identifier of the metric (see standard vocabulary below) | | `label` | string | Human-readable name | | `description` | string | Optional longer description | | `unit` | string | Measurement unit, always an SI base unit (`byte`, `count`, `second`) | | `kind` | string | `gauge` (point-in-time value) or `counter` (accumulated over the period) | | `aggregation` | string | How to reduce the metric over a period: `last`, `max`, `avg`, `sum` | | `billable` | boolean | Hint: this metric is meant to drive billing | | `product_ref` | string | Optional. Product/service reference the metric maps to, for automatic line mapping | ### gauge vs counter The distinction is essential to bill correctly over a period: * **gauge** -- a value that exists at a point in time (storage used, number of users). The server states how to reduce it over the period through `aggregation` (`last` = value at end of period, `max` = peak, `avg` = average). * **counter** -- a value accumulated during the period (bandwidth, sent emails). It is naturally reduced with `aggregation: "sum"`. The client MUST honor the declared `aggregation` and never guess. ### Units Units are always expressed as **SI base units**, never as multiples, so any tool can convert consistently: | Unit | Meaning | |---|---| | `byte` | bytes (not KB / MB / GB) | | `count` | a plain integer count | | `second` | seconds (not minutes / hours) | ### Standard metric vocabulary To let tools auto-map metrics to products, common metrics SHOULD reuse these `code` values. Services MAY expose additional custom metrics prefixed with `x-` (for example `x-antispam_rules`). | Code | Unit | Typical kind | Description | |---|---|---|---| | `storage_bytes` | `byte` | gauge | Disk space occupied | | `bandwidth_bytes` | `byte` | counter | Network traffic over the period | | `user_count` | `count` | gauge | Number of user accounts | | `mailbox_count` | `count` | gauge | Number of mailboxes | | `mailbox_quota_bytes` | `byte` | gauge | Total mailbox quota allocated | | `email_sent_count` | `count` | counter | Emails sent over the period | | `request_count` | `count` | counter | Requests served over the period | | `compute_seconds` | `second` | counter | Compute time consumed | ### Metric values for an account * **Method**: `GET /obapi/v1/usage` * **Headers**: `Authorization: Bearer {apikey}` | Parameter | Type | Required | Description | |---|---|---|---| | `account` | string | yes | Account identifier -- the customer email address on the service | | `period` | string | no | Billing period `YYYY-MM` (default: current month) | | `metrics` | string | no | Comma-separated list of metric codes to restrict the response | #### Account identification The `account` parameter is the **email address** of the customer account on the service. It is the natural business key for mail, storage and proxy hosting, and the central billing system already knows it from the customer record. A customer holding several accounts on the same service (several mailboxes, several users) is represented as several accounts: one request per account. The central system is responsible for summing per-customer if needed. #### Response ```json { "account": "client@example.com", "period": { "start": "2026-06-01", "end": "2026-06-30", "granularity": "month" }, "measures": [ { "code": "storage_bytes", "value": "48318382080", "unit": "byte", "captured_at": "2026-06-30T23:59:59Z" }, { "code": "user_count", "value": "12", "unit": "count" }, { "code": "bandwidth_bytes", "value": "912680550400", "unit": "byte" } ] } ``` #### Measure object | Field | Type | Description | |---|---|---| | `code` | string | Metric code, matching a `code` from the catalog | | `value` | string | Value as a decimal string (never a float) in the metric unit | | `unit` | string | Unit of the value, echoed from the catalog | | `captured_at` | string | Optional. ISO 8601 timestamp when a gauge value was read | ### Errors If the account is unknown to the service: ```json { "error": { "type": "not_found", "code": "ACCOUNT_NOT_FOUND", "message": "No account matches the provided identifier" } } ``` ### Reference implementation A single-file PHP example implementing this capability on top of a **Nextcloud** instance is available in the repository: `examples/usage-nextcloud.php`. It is a complete minimal OBAPI server (discovery + `usage` only, no dependency but curl) that maps a customer account (email) to a Nextcloud group and reports the group's total storage used and user count via the OCS Provisioning API. Example calls: ``` GET / -> { "capabilities": ["usage"], ... } GET /usage/metrics -> { "metrics": [ storage_bytes, user_count ] } GET /usage?account=client@example.com&period=2026-06 -> { "measures": [ ... ] } ``` --- # Projects Source: https://obapi.org/v1/projects ## Projects Shared project tracking between entities. ### Endpoints * `GET /obapi/v1/projects` -- list * `GET /obapi/v1/projects/{id}` -- single with tasks ### Parameters `page`, `per_page`, `status`, `sort` ### Status values | Value | Description | |---|---| | `draft` | Draft project | | `validated` | Active project | | `closed` | Closed project | ### Response (list) ```json { "items": [ { "id": "15", "ref": "PJ2405-0003", "title": "ERP Migration Q3", "date_start": "2024-07-01", "date_end": "2024-09-30", "status": "validated" } ], "pagination": { "..." } } ``` ### Response (single) ```json { "project": { "id": "15", "ref": "PJ2405-0003", "title": "ERP Migration Q3", "description": "Full migration of legacy ERP to cloud platform", "date_start": "2024-07-01", "date_end": "2024-09-30", "created_at": "2024-05-01T10:00:00Z", "status": "validated", "public_note": "", "tasks": [ { "id": "42", "ref": "TK2405-0010", "label": "Data migration", "date_start": "2024-07-01", "date_end": "2024-07-31", "planned_hours": "120.00", "spent_hours": "45.00", "progress": 35, "priority": 2, "status": "validated" }, { "id": "43", "ref": "TK2405-0011", "label": "User acceptance testing", "date_start": "2024-08-01", "date_end": "2024-08-31", "planned_hours": "80.00", "spent_hours": "0.00", "progress": 0, "priority": 1, "status": "draft" } ] } } ``` --- # Tasks Source: https://obapi.org/v1/tasks ## Tasks Project tasks. A task always belongs to a project. ### Endpoints * `GET /obapi/v1/tasks` -- list (optionally filtered by project) * `GET /obapi/v1/tasks/{id}` -- single * `GET /obapi/v1/projects/{id}/tasks` -- list tasks for a specific project ### Parameters `page`, `per_page`, `project_id`, `status`, `sort` ### Response (list) ```json { "items": [ { "id": "42", "ref": "TK2405-0010", "label": "Data migration", "project_ref": "PJ2405-0003", "date_start": "2024-07-01", "date_end": "2024-07-31", "progress": 35, "status": "validated" } ], "pagination": { "..." } } ``` ### Response (single) ```json { "task": { "id": "42", "ref": "TK2405-0010", "label": "Data migration", "description": "Migrate all customer and invoice data from legacy system", "project_ref": "PJ2405-0003", "date_start": "2024-07-01", "date_end": "2024-07-31", "planned_hours": "120.00", "spent_hours": "45.00", "progress": 35, "priority": 2, "created_at": "2024-05-01T10:30:00Z", "updated_at": "2024-07-15T16:00:00Z", "status": "validated", "public_note": "" } } ``` ### Notes - `planned_hours` and `spent_hours` are string representations of decimal hours. - `progress` is a percentage from 0 to 100. - `priority` is an integer (higher value = higher priority). --- # Expense Reports Source: https://obapi.org/v1/expense-reports ## Expense Reports Employee expense claims. ### Endpoints * `GET /obapi/v1/expense-reports` -- list * `GET /obapi/v1/expense-reports/{id}` -- single with lines * `GET /obapi/v1/download/{id}?type=expense-report` -- PDF ### Parameters `page`, `per_page`, `date_start`, `date_end`, `status`, `sort` ### Status values | Value | Description | |---|---| | `draft` | Draft | | `validated` | Validated by employee | | `approved` | Approved by manager | | `paid` | Reimbursed | | `refused` | Refused | | `cancelled` | Cancelled | ### Response (list) ```json { "items": [ { "id": "75", "ref": "NDF2405-0008", "date_start": "2024-05-01", "date_end": "2024-05-31", "status": "approved", "paid": false, "total_excl_tax": "342.50", "total_incl_tax": "411.00" } ], "pagination": { "..." } } ``` ### Response (single) ```json { "expense_report": { "id": "75", "ref": "NDF2405-0008", "date_start": "2024-05-01", "date_end": "2024-05-31", "created_at": "2024-06-01T09:00:00Z", "updated_at": "2024-06-03T14:00:00Z", "validated_at": "2024-06-01T09:00:00Z", "approved_at": "2024-06-03T14:00:00Z", "status": "approved", "paid": false, "payment_method": "Bank transfer", "total_excl_tax": "342.50", "total_vat": "68.50", "total_incl_tax": "411.00", "multicurrency_code": "EUR", "refuse_reason": "", "cancel_reason": "", "public_note": "", "lines": [ { "id": "150", "position": 1, "fee_type": "Train ticket", "date": "2024-05-12", "comments": "Paris - Lyon round trip", "quantity": "1.00", "unit_value": "125.00", "vat_rate": "10.000", "total_excl_tax": "113.64", "total_vat": "11.36", "total_incl_tax": "125.00", "project_ref": "PJ2405-0003" }, { "id": "151", "position": 2, "fee_type": "Hotel", "date": "2024-05-12", "comments": "1 night in Lyon", "quantity": "1.00", "unit_value": "156.00", "vat_rate": "20.000", "total_excl_tax": "130.00", "total_vat": "26.00", "total_incl_tax": "156.00", "project_ref": "PJ2405-0003" }, { "id": "152", "position": 3, "fee_type": "Meals", "date": "2024-05-12", "comments": "Dinner with client", "quantity": "1.00", "unit_value": "130.00", "vat_rate": "20.000", "total_excl_tax": "98.86", "total_vat": "31.14", "total_incl_tax": "130.00", "project_ref": "" } ] } } ``` ### Download PDF `GET /obapi/v1/download/{id}?type=expense-report` --- # BOMs Source: https://obapi.org/v1/boms ## Bills of Materials (BOMs) Bill of materials for manufacturing. Describes the components needed to produce a finished product. ### Endpoints * `GET /obapi/v1/boms` -- list * `GET /obapi/v1/boms/{id}` -- single with lines ### Parameters `page`, `per_page`, `status`, `product_ref`, `sort` ### Status values | Value | Description | |---|---| | `draft` | Draft BOM | | `validated` | Active BOM | | `closed` | Obsolete / closed | ### Response (list) ```json { "items": [ { "id": "8", "ref": "BOM2405-0002", "label": "Assembled widget v2", "product_ref": "WIDGET-V2", "quantity": "1.00", "status": "validated" } ], "pagination": { "..." } } ``` ### Response (single) ```json { "bom": { "id": "8", "ref": "BOM2405-0002", "label": "Assembled widget v2", "bom_type": "manufacturing", "description": "Assembly instructions for Widget V2", "product_ref": "WIDGET-V2", "product_label": "Assembled Widget V2", "quantity": "1.00", "duration": "3600", "efficiency": "0.95", "warehouse": "Production warehouse", "created_at": "2024-03-10T09:00:00Z", "validated_at": "2024-03-15T10:00:00Z", "updated_at": "2024-03-15T10:00:00Z", "status": "validated", "public_note": "", "lines": [ { "id": "20", "position": 1, "product_ref": "COMP-A1", "product_label": "Component A1", "description": "Main circuit board", "quantity": "1.00", "quantity_frozen": false, "disable_stock_change": false, "efficiency": "1.00", "child_bom_ref": "" }, { "id": "21", "position": 2, "product_ref": "COMP-B2", "product_label": "Component B2", "description": "Mounting bracket", "quantity": "4.00", "quantity_frozen": false, "disable_stock_change": false, "efficiency": "0.98", "child_bom_ref": "" }, { "id": "22", "position": 3, "product_ref": "ENCL-01", "product_label": "Enclosure standard", "description": "Outer casing", "quantity": "1.00", "quantity_frozen": true, "disable_stock_change": false, "efficiency": "1.00", "child_bom_ref": "BOM2404-0005" } ] } } ``` ### BOM types | Value | Description | |---|---| | `manufacturing` | Standard assembly | | `disassembly` | Disassembly / recycling | --- # Manufacturing Orders Source: https://obapi.org/v1/manufacturing-orders ## Manufacturing Orders Production runs based on a Bill of Materials. ### Endpoints * `GET /obapi/v1/manufacturing-orders` -- list * `GET /obapi/v1/manufacturing-orders/{id}` -- single with lines ### Parameters `page`, `per_page`, `date_start`, `date_end`, `status`, `sort` ### Status values | Value | Description | |---|---| | `draft` | Draft MO | | `validated` | Validated, ready to produce | | `in_progress` | Production in progress | | `produced` | Production finished | | `cancelled` | Cancelled | ### Response (list) ```json { "items": [ { "id": "12", "ref": "MO2405-0001", "label": "Widget V2 - Batch 50", "product_ref": "WIDGET-V2", "quantity": "50.00", "date_start_planned": "2024-06-01", "date_end_planned": "2024-06-15", "status": "in_progress" } ], "pagination": { "..." } } ``` ### Response (single) ```json { "manufacturing_order": { "id": "12", "ref": "MO2405-0001", "label": "Widget V2 - Batch 50", "mrp_type": "manufacturing", "product_ref": "WIDGET-V2", "product_label": "Assembled Widget V2", "bom_ref": "BOM2405-0002", "quantity": "50.00", "warehouse": "Production warehouse", "date_start_planned": "2024-06-01", "date_end_planned": "2024-06-15", "created_at": "2024-05-20T11:00:00Z", "validated_at": "2024-05-25T09:00:00Z", "updated_at": "2024-06-05T17:00:00Z", "status": "in_progress", "project_ref": "", "public_note": "", "lines": [ { "id": "30", "position": 1, "product_ref": "COMP-A1", "product_label": "Component A1", "quantity": "50.00", "warehouse": "Production warehouse", "role": "consumed", "origin_type": "", "origin_id": "" }, { "id": "31", "position": 2, "product_ref": "COMP-B2", "product_label": "Component B2", "quantity": "200.00", "warehouse": "Production warehouse", "role": "consumed", "origin_type": "", "origin_id": "" }, { "id": "32", "position": 3, "product_ref": "WIDGET-V2", "product_label": "Assembled Widget V2", "quantity": "50.00", "warehouse": "Finished goods", "role": "produced", "origin_type": "", "origin_id": "" } ] } } ``` ### Line roles | Value | Description | |---|---| | `consumed` | Raw material / component consumed | | `produced` | Finished product produced | --- # Warehouses Source: https://obapi.org/v1/warehouses ## Warehouses Stock locations and storage facilities. ### Endpoints * `GET /obapi/v1/warehouses` -- list * `GET /obapi/v1/warehouses/{id}` -- single ### Parameters `page`, `per_page`, `status`, `sort` ### Status values | Value | Description | |---|---| | `open` | Active warehouse | | `closed` | Closed warehouse | ### Response (list) ```json { "items": [ { "id": "3", "ref": "WH-MAIN", "label": "Main warehouse", "city": "Lyon", "status": "open" }, { "id": "5", "ref": "WH-PROD", "label": "Production warehouse", "city": "Lyon", "status": "open" } ], "pagination": { "..." } } ``` ### Response (single) ```json { "warehouse": { "id": "3", "ref": "WH-MAIN", "label": "Main warehouse", "description": "Central storage facility", "address": "12 rue de l'Industrie", "zip": "69003", "city": "Lyon", "country": "FR", "phone": "+33 4 72 00 00 00", "status": "open", "parent_warehouse_ref": "" } } ``` ### Notes - `parent_warehouse_ref` allows hierarchical warehouse structures (e.g. zones within a warehouse). - `country` uses ISO 3166-1 alpha-2 format. --- # Members Source: https://obapi.org/v1/members ## Members Association and cooperative members. ### Endpoints * `GET /obapi/v1/members` -- list * `GET /obapi/v1/members/{id}` -- single ### Parameters `page`, `per_page`, `status`, `type`, `sort` ### Status values | Value | Description | |---|---| | `draft` | Draft / pending validation | | `validated` | Active member | | `excluded` | Excluded | | `resigned` | Resigned | ### Response (list) ```json { "items": [ { "id": "120", "ref": "ADH-0120", "type": "Individual", "lastname": "Martin", "firstname": "Sophie", "company": "", "email": "sophie.martin@example.com", "date_subscription_end": "2025-12-31", "status": "validated" } ], "pagination": { "..." } } ``` ### Response (single) ```json { "member": { "id": "120", "ref": "ADH-0120", "type": "Individual", "civility": "Mme", "lastname": "Martin", "firstname": "Sophie", "company": "", "address": "45 avenue des Fleurs", "zip": "75015", "city": "Paris", "state": "", "country": "FR", "phone": "+33 6 12 34 56 78", "email": "sophie.martin@example.com", "date_birth": "1985-03-15", "date_subscription_start": "2024-01-01", "date_subscription_end": "2025-12-31", "subscription_amount": "50.00", "status": "validated", "public_note": "" } } ``` ### Notes - `type` refers to the membership type (e.g. "Individual", "Corporate", "Student"). - `country` uses ISO 3166-1 alpha-2 format. --- # Categories Source: https://obapi.org/v1/categories ## Categories Shared classification and tagging system. Categories can be applied to multiple object types. ### Endpoints * `GET /obapi/v1/categories` -- list * `GET /obapi/v1/categories/{id}` -- single ### Parameters `page`, `per_page`, `type`, `parent_id`, `sort` ### Category types | Value | Description | |---|---| | `product` | Product categories | | `thirdparty` | Third-party categories | | `contact` | Contact categories | | `member` | Member categories | | `project` | Project categories | ### Response (list) ```json { "items": [ { "id": "10", "label": "Electronics", "type": "product", "parent_label": "", "color": "#3498DB" }, { "id": "11", "label": "Sensors", "type": "product", "parent_label": "Electronics", "color": "#2ECC71" }, { "id": "20", "label": "Key accounts", "type": "thirdparty", "parent_label": "", "color": "#E74C3C" } ], "pagination": { "..." } } ``` ### Response (single) ```json { "category": { "id": "11", "label": "Sensors", "description": "Electronic sensors and probes", "color": "#2ECC71", "type": "product", "parent_id": "10", "parent_label": "Electronics" } } ``` ### Notes - Categories support hierarchy via `parent_id`. - `color` is a hex color code for UI display. - Use `type` parameter to filter categories by object type. --- # Demonstration Source: https://obapi.org/v1/demo ## Demonstration ### Proof of concept An OBAPI server built on Dolibarr ERP, queried by a simple PHP command-line client: ``` $ php obapi-client.php Connecting to your OBAPI server: http://192.168.16.183/16/obapi/v1/invoices Invoices listing: +------+-------------+------------+----------------------------------------+-----------+-----------+--------+ | ID | Ref | Date | Label | Excl. tax | Incl. tax | Status | +------+-------------+------------+----------------------------------------+-----------+-----------+--------+ | 54 | FA1912-0053 | 2019-12-12 | | 1 527.00 | 1 832.40 | paid | | 57 | FA2001-0002 | 2020-01-22 | | 1 527.00 | 1 832.40 | paid | | 60 | FA2001-0004 | 2020-01-31 | | 12 500.00 | 15 000.00 | paid | | 62 | FA2002-0006 | 2020-02-21 | | 1 527.00 | 1 832.40 | paid | | 67 | FA2003-0011 | 2020-03-19 | | 1 527.00 | 1 832.40 | paid | | 70 | FA2004-0014 | 2020-04-18 | | 1 527.00 | 1 832.40 | paid | | 850 | FA2209-0646 | 2022-09-09 | | 1 527.00 | 1 832.40 | paid | | 1081 | FA2212-0842 | 2022-12-06 | Accompagnement technique Novembre 2022 | 1 527.00 | 1 832.40 | paid | +------+-------------+------------+----------------------------------------+-----------+-----------+--------+ ``` ### Same client, different provider The same client works against a completely different backend (not Dolibarr): ``` $ php obapi-client.php --server doliscan.devtemp.fr Connecting to your OBAPI server: https://doliscan.devtemp.fr/obapi/v1/invoices Invoices listing: +----------+----------+------------+----------+-----------+-----------+--------+ | ID | Ref | Date | Label | Excl. tax | Incl. tax | Status | +----------+----------+------------+----------+-----------+-----------+--------+ | 10215488 | 01025488 | 2022-11-05 | Nov.2022 | 9.99 | 11.99 | paid | | 10215496 | 01025496 | 2022-12-05 | Dec.2022 | 9.99 | 11.99 | paid | +----------+----------+------------+----------+-----------+-----------+--------+ ``` **Zero code change** between the two providers. That's the point. ### What the API returns Behind the scenes, the client makes a simple HTTP call: ```bash curl -H "Authorization: Bearer abc123" \ https://provider.example.com/obapi/v1/invoices ``` And gets back standard JSON: ```json { "items": [ { "id": "850", "ref": "FA2209-0646", "date_invoice": "2022-09-09", "status": "paid", "total_excl_tax": "1527.00", "total_vat": "305.40", "total_incl_tax": "1832.40" } ], "pagination": { "page": 1, "per_page": 50, "total_items": 8, "total_pages": 1 } } ``` ### Download a PDF ```bash curl -H "Authorization: Bearer abc123" \ -o FA2209-0646.pdf \ "https://provider.example.com/obapi/v1/download/850?type=invoice" ``` The PDF lands on your disk. No portal, no login form, no CAPTCHA. ### Beyond invoices The same pattern works for all 24 OBAPI objects: ```bash # List orders curl -H "Authorization: Bearer abc123" \ https://provider.example.com/obapi/v1/orders # List products curl -H "Authorization: Bearer abc123" \ https://provider.example.com/obapi/v1/products # List supplier invoices curl -H "Authorization: Bearer abc123" \ https://provider.example.com/obapi/v1/supplier-invoices # Discover server capabilities curl -H "Authorization: Bearer abc123" \ https://provider.example.com/obapi/v1 ``` --- # API Explorer Source: https://obapi.org/v1/explorer ## API Explorer Interactive reference generated from the [OpenAPI specification](/assets/openapi.yaml).
---