Appearance
OSERP API Library
The OSERP API is a versioned REST API for the web app, mobile clients, integrations, BI, POS, and AI tools. Base URL:
text
https://api.example.com/api/v1The running application sets the global prefix to /api/v1. Replace the host with your deployment URL. This library describes routes present in the repository; a route marked configured still requires the caller’s tenant, company, and permission scope.
1. Authenticate and scope every request
Login
bash
curl -X POST "$OSERP_API/auth/login" \
-H 'Content-Type: application/json' \
-H 'X-Tenant-Id: tenant_demo' \
-d '{"email":"admin@example.com","password":"change-me"}'The response returns an access token and refresh token. Send the access token on every guarded call:
http
Authorization: Bearer <access-token>
X-Tenant-Id: tenant_demo
X-Organization-Id: org_demo
X-Company-Id: company_uaeThe API enforces tenant isolation. Never accept a company, branch, warehouse, or ledger ID from an untrusted client without checking that it belongs to the authenticated scope.
Token lifecycle
| Method | Endpoint | Use |
|---|---|---|
| GET | /auth/lookup?email= | Find the tenant invitation/account before login |
| POST | /auth/login | Create access and refresh tokens |
| POST | /auth/unlock | Re-authenticate an idle-locked session |
| POST | /auth/refresh | Rotate a refresh token |
| POST | /auth/logout | Revoke the current session |
| POST | /auth/change-password | Change the authenticated password |
2. Response contract
Successful calls normally return:
json
{"success":true,"data":{"id":"item_01","code":"CHAIR-001"},"message":""}Validation or business errors return a readable failure. Treat non-2xx responses and success:false as failures; do not infer success from HTTP 200 alone.
json
{"success":false,"error":{"code":"VALIDATION_ERROR","message":"quantity must be greater than zero","details":[]}}Lists commonly accept search, page, limit, sorting, and module-specific filters. Monetary values are decimal strings or JSON numbers interpreted by the server; never calculate money with binary floating point in an integration.
3. CRUD endpoint catalogue
Companies and organisation
| CRUD | Endpoint | Sample |
|---|---|---|
| List | GET /companies | ?page=1&limit=50&search=Dubai |
| Create | POST /companies | { "name":"Virtux UAE", "baseCurrency":"AED" } |
| Update | PATCH /companies/:id | { "name":"Virtux UAE FZ-LLC" } |
| Delete | DELETE /companies/:id | Deactivate only when policy permits |
| Current tenant | GET /tenants/current | Resolves caller scope |
| Organisations | GET /organizations | List organisations in scope |
Items, prices, stock and warehouses
| CRUD | Endpoint | Sample |
|---|---|---|
| List items | GET /items | ?search=chair&categoryId=cat_furniture |
| Read item | GET /items/:id | Returns master and configured attributes |
| Create item | POST /items | { "code":"CHAIR-001", "name":"Oak chair", "uom":"PCS", "trackBatch":false } |
| Update item | PATCH /items/:id | { "name":"Oak dining chair" } |
| Delete item | DELETE /items/:id | Use only when no posted history exists |
| Stock | GET /items/:id/stock | ?warehouseId=wh_dubai |
| Price for customer | GET /items/:id/price | ?customerId=bp_lulu&branchId=br_dubai |
| Categories | GET/POST/PATCH/DELETE /items/categories[/:catId] | Create and maintain item hierarchy |
| Price lists | GET/POST/PATCH /items/price-lists[/:priceListId] | Bulk prices: POST /items/price-lists/:priceListId/bulk |
| Warehouses | GET/POST/PATCH/DELETE /warehouses[/:id] | { "code":"WH-DXB", "name":"Dubai DC" } |
| Scan | GET /items/scan/:code | Barcode or item code lookup |
Business partners (customers and suppliers)
| CRUD | Endpoint | Sample |
|---|---|---|
| Search | GET /business-partners/ref/search?search=Lulu | Fast picker lookup |
| List | GET /business-partners | Filter by role, group, active state |
| Read | GET /business-partners/:id | Full master, addresses, contacts |
| Create | POST /business-partners | { "code":"CUST-001", "name":"Lulu Hypermarket", "roles":["CUSTOMER"] } |
| Update | PATCH /business-partners/:id | Change safe master fields |
| Delete | DELETE /business-partners/:id | Blocked when posted documents exist |
| Address | POST/PATCH/DELETE /business-partners/:id/addresses[/:addrId] | Bill-to and ship-to |
| Contact | POST/PATCH/DELETE /business-partners/:id/contacts[/:contactId] | Buyer and finance contacts |
| Credit profile | POST /business-partners/:id/credit-profile | Limit, terms, risk policy |
| Block/unblock | POST /business-partners/:id/block / unblock | Controlled credit action |
Sales documents and the 14-stage lifecycle
Sales documents are exposed through the process-workspace controller. The same resource carries quotation, order, delivery, invoice, payment, return, credit-note, collection, and closure stages.
| CRUD / action | Endpoint | Sample |
|---|---|---|
| List | GET /process-workspaces?processType=SALES | Pipeline and stage filters |
| Read | GET /process-workspaces/:id | Header, lines, stage state |
| Create | POST /process-workspaces | See complete example below |
| Update header | PATCH /process-workspaces/:id/header | Dates, terms, warehouse, dimensions |
| Add line | POST /process-workspaces/:id/lines | Item, quantity, price, tax, warehouse |
| Update line | PATCH /process-workspaces/:id/lines/:lineId | Correct an unposted line |
| Delete line | DELETE /process-workspaces/:id/lines/:lineId | Draft/unposted only |
| Preview submit | POST /process-workspaces/:id/submit-preview | Shows missing fields and gates |
| Submit | POST /process-workspaces/:id/submit | Commits the current stage |
| Advance | POST /process-workspaces/:id/advance | Move to next configured stage |
| Advance preview | POST /process-workspaces/:id/advance-preview | Safe dry-run before transition |
| Chain | GET /process-workspaces/:id/chain | All related stages |
| Journal | GET /process-workspaces/:id/journal | Posted accounting impact |
| Reverse | POST /process-workspaces/:id/reverse | Controlled reversal |
Create a quotation/order draft:
bash
curl -X POST "$OSERP_API/process-workspaces" \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-H 'X-Tenant-Id: tenant_demo' -H 'X-Company-Id: company_uae' \
-d '{
"processType":"SALES", "stage":"QUOTATION", "counterpartyId":"bp_lulu",
"documentDate":"2026-09-15", "postingDate":"2026-09-15",
"currencyCode":"AED", "warehouseId":"wh_dubai", "paymentTermsId":"net30",
"lines":[{"itemId":"item_chair_001","description":"Oak chair","quantity":100,"uom":"PCS","unitPrice":125.00,"discountPct":5,"taxPct":5,"warehouseId":"wh_dubai"}]
}'Advance only after checking the preview:
bash
curl -X POST "$OSERP_API/process-workspaces/doc_123/advance-preview" -H "Authorization: Bearer $TOKEN"
curl -X POST "$OSERP_API/process-workspaces/doc_123/advance" -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' -d '{"note":"Customer PO accepted"}'Orders, POS and ecommerce
| Module | CRUD / action endpoints |
|---|---|
| Orders | GET/POST /orders, GET /orders/:id, POST /orders/:id/advance, /delivery, /cancel, /attach, /assign |
| POS sales | POST /pos/checkout, GET /pos/sales, GET /pos/sales/:id, POST /pos/sales/:id/void |
| POS returns | POST /pos/returns/preview, POST /pos/returns |
| POS customers | GET/POST /pos/customers, GET /pos/customers/:id/credit, /history |
| Ecommerce catalogue | GET/PATCH /ecommerce/products[/:id], GET/PATCH /ecommerce/categories[/:id] |
| Ecommerce stores | GET/POST/PATCH/DELETE /ecommerce/stores[/:id] |
Accounting, vouchers and reports
| CRUD / query | Endpoint |
|---|---|
| Groups | GET/POST /accounting/groups, PATCH /accounting/groups/:id |
| Ledgers | GET/POST /accounting/ledgers, PATCH /accounting/ledgers/:id |
| Vouchers | GET/POST /vouchers, GET /vouchers/:id, POST /vouchers/:id/reverse |
| Trial balance | GET /accounting/trial-balance |
| P&L / balance sheet | GET /accounting/profit-and-loss, GET /accounting/balance-sheet |
| General ledger | GET /accounting/general-ledger |
| Statements | GET /accounting/statement/:direction |
| Reconciliation | GET/POST /accounting/reconcile/:direction/allocate, history and unallocate routes |
| Tax summary | GET /accounting/tax-summary |
Users, roles, projects and HR
| Module | CRUD endpoints |
|---|---|
| Users | GET/POST /users, GET /users/:id, PATCH /users/:id, DELETE /users/:id, POST /users/invite |
| Roles | GET/POST /roles, GET /roles/:id, PATCH /roles/:id, DELETE /roles/:id |
| Projects | GET/POST /projects, GET /projects/:id, PATCH /projects/:id, DELETE /projects/:id |
| Employees | GET /hr/employees, GET /hr/employees/:id, PUT /hr/employees, PUT /hr/employments |
| Payroll | GET/POST /payroll/runs, GET /payroll/runs/:id, POST /payroll/runs/:id/calculate, /approve, /post |
4. Integration safety
- Send a unique
Idempotency-Keyon invoice, payment, voucher, checkout, and stock-moving writes. Retry the same key; never create a new key for a network timeout. - Store access and refresh tokens in a secret store, never browser local storage for server integrations.
- Use permission scopes such as
sales:read,sales:write,inventory:read,customers:write, andreports:read. - Use webhook HMAC verification for external callbacks; retain the raw request body before parsing.
- Log request ID, tenant, company, endpoint, actor, latency, and result—but never passwords or bearer tokens.
- Use
advance-previewandsubmit-previewbefore a batch transition. A successful HTTP response does not mean a document posted if its stage state is still a draft.
5. Practical error guide
| Symptom | Check |
|---|---|
401 | Access token expired; call /auth/refresh |
403 | User/API key lacks permission or stage access |
404 | ID is outside tenant/company scope or does not exist |
| Missing stage fields | Read submit-preview; fill Stage details such as customer PO, transporter, payment mode, or cheque number |
| Invoice not posting | Period lock, numbering, approval, tax, FX rate, or posting mapping |
| Duplicate supplier/payment | Reuse the same idempotency key and inspect the existing document |
For the complete implementation-level inventory, use the controller source and the repository API strategy. For business meaning, pair this library with the sales field guide and OSERP Atlas.
6. Resource contract cards for connector authors
The following cards are the minimum contract a connector should implement for each resource. Names are illustrative and must be checked against the deployed OpenAPI document. The important discipline is consistent identity, scope, precision, versioning, and state transitions.
Business partner card
GET /business-partners accepts tenantId, companyId, type, updatedAfter, status, limit, and cursor. Return id, code, name, type, taxRegistration, countryCode, currencyCode, paymentTermsId, status, version, createdAt, updatedAt, and scope identifiers. A policy-safe 404 is correct when an ID exists in another tenant.
json
{
"id": "bp_lulu_001",
"code": "LULU-UAE",
"name": "Demo Lulu Hypermarket LLC",
"type": "CUSTOMER",
"taxRegistration": "AE123456789",
"countryCode": "AE",
"currencyCode": "AED",
"paymentTermsId": "net30",
"status": "ACTIVE",
"version": 4,
"scope": {"tenantId":"tenant_demo","companyId":"company_uae"}
}POST requires an Idempotency-Key; replaying the same body and key returns the original resource. PATCH accepts mutable commercial fields only and requires If-Match: 4 or an equivalent version. Tax registration, legal identity, and historical currency are immutable after first posting; create a versioned amendment instead.
Item and warehouse card
POST /inventory/items creates the catalogue identity. Item code, UoM, valuation method, tax class, batch or serial rule, and active status are explicit fields. PATCH cannot change valuation method when posted stock exists. GET /inventory/stock is a position query, not a transaction: it returns warehouse, bin, lot or serial, available, reserved, quarantine, and unit-cost quantities.
json
{
"itemCode": "CHAIR-OAK-001",
"description": "Oak chair",
"baseUom": "PCS",
"valuationMethod": "MOVING_AVERAGE",
"batchManaged": false,
"taxCode": "VAT5",
"status": "ACTIVE"
}Stock-moving writes must include source document, warehouse, quantity, UoM, reason, and idempotency key. Do not implement a generic DELETE /stock; use receipt, issue, transfer, return, or approved adjustment so the ledger remains auditable.
Sales document card
The sales document resource has a header and lines. The header carries company, branch, customer, document and posting dates, currency, exchange-rate source, price list, payment terms, tax profile, warehouse, project, and external reference. Each line carries item or service, description, quantity, UoM, unit price, discount, tax, warehouse, project, and dimensions.
json
{
"documentType":"INVOICE",
"customerId":"bp_lulu_001",
"documentDate":"2026-09-17",
"postingDate":"2026-09-17",
"currencyCode":"AED",
"lines":[{"itemId":"item_chair_001","quantity":10,"uom":"PCS","unitPrice":125.00,"discountPct":5,"taxCode":"VAT5"}]
}The server recalculates totals and tax; clients must not submit a trusted grand total. A response should expose net, tax, gross, rounding adjustment, status, version, journal status, and correlation ID. POST /sales/:id/advance-preview must be safe to repeat and must not create a journal. POST /sales/:id/advance performs the state transition after validations pass.
Payment and reconciliation card
Payment writes require payer, bank or cash account, value date, currency, amount, external reference, allocation, and fee. Allocation is a separate child operation because a receipt can be split across invoices. A payment response returns unapplied amount and allocation version. An allocation against a closed or foreign-company invoice is blocked.
json
{
"payerId":"bp_lulu_001",
"bankAccountId":"bank_dubai_01",
"valueDate":"2026-09-17",
"currencyCode":"AED",
"amount":1312.50,
"externalReference":"GATEWAY-8842",
"fee":5.00
}Reconciliation endpoints should return matched, unmatched, partially matched, and disputed states. Unallocate is a controlled reversal that requires reason and permission; it is not a silent delete of the original match.
Journal and reversal card
POST /vouchers requires company, book, posting date, currency context, source document, description, and balanced lines. Each line has account role or account ID, debit or credit, amount, tax, dimensions, and source reference. Money uses decimal strings or a fixed-precision representation; never binary floating point.
json
{
"bookId":"IFRS-AED",
"postingDate":"2026-09-17",
"sourceType":"MANUAL_ADJUSTMENT",
"lines":[
{"accountId":"510100","debit":"1000.00","credit":"0.00","costCentre":"CC-DXB"},
{"accountId":"110010","debit":"0.00","credit":"1000.00","costCentre":"CC-DXB"}
]
}The server verifies debit equals credit at book precision, account activity, period status, required dimensions, permission, and duplicate source reference. Reversal creates a linked opposite journal with reason and actor; it does not mutate the posted voucher.
7. A connector’s end-to-end acceptance script
- Authenticate and record token scope, tenant, company, and correlation ID.
- Read the metadata or schema endpoint and validate field names, enum values, precision, and required dimensions.
- Create or locate a business partner using an idempotency key; replay the request and prove one record exists.
- Create an item and confirm that the response includes stable ID, code, version, and scope.
- Create a draft sales document with two lines, then call preview and inspect calculated net, tax, gross, and mapping path.
- Attempt a duplicate external reference, a closed-period date, a missing dimension, and an out-of-scope ID; prove each refusal has no partial posting.
- Advance the document, read the resulting journal, and reconcile line totals at document and base currency precision.
- Post a payment with a bank reference, replay it, allocate it to the invoice, and verify unapplied amount is zero.
- Receive a webhook, verify HMAC over the raw body, store event ID, replay it, and prove the handler is idempotent.
- Export audit events and retain request, response, actor, scope, version, timestamp, and correlation ID for the evidence pack.
This script is the minimum baseline for an AI agent, marketplace connector, bank integration, or data migration tool. A green HTTP status alone is not acceptance: the connector must prove business state, accounting state, scope isolation, and safe retry behavior.