CloudPOS REST API v2
One consistent, secured REST API for every CloudPOS installation. Read and manage customers, suppliers, billers, products, categories, warehouses, tax rates and more, and read sales, purchases, stock, payments and expenses — with the same permissions each user has in the admin panel.
Quick start
In your CloudPOS admin open Settings → API keys and create a key (optionally restrict it to your server’s IP address and a warehouse). Make sure API is enabled in system settings.
Send the key plus your normal CloudPOS username and password to POST /api/v2/auth/token. You receive an access token (1 hour) and a refresh token (14 days).
Send both api-key and Authorization: Bearer <token> on every request. Without both you get 401.
# 1) get a token (api-key only)
curl -X POST https://YOUR-HOST/api/v2/auth/token \
-H "api-key: YOUR_API_KEY" -H "Content-Type: application/json" \
-d '{"username":"owner","password":"your-password"}'
# 2) use it (api-key AND bearer)
curl "https://YOUR-HOST/api/v2/customers?per_page=10&q=ali" \
-H "api-key: YOUR_API_KEY" -H "Authorization: Bearer cp2_xxxxxxxx"
# 3) create / update / delete
curl -X POST https://YOUR-HOST/api/v2/customers -H "api-key: ..." -H "Authorization: Bearer ..." -H "Content-Type: application/json" -d '{"name":"Ali Traders","phone":"0300-1234567"}'
curl -X PATCH https://YOUR-HOST/api/v2/customers/42 -H "api-key: ..." -H "Authorization: Bearer ..." -H "Content-Type: application/json" -d '{"city":"Lahore"}'
curl -X DELETE https://YOUR-HOST/api/v2/customers/42 -H "api-key: ..." -H "Authorization: Bearer ..."
Replace YOUR-HOST with your CloudPOS address (for example https://yourshop.cloudpos.pk). Every installation has its own API at /api/v2.
Test it on this page
The console below calls your CloudPOS server straight from your browser. Nothing is sent to cloudpos.pk, the password and tokens live only in this tab’s memory and are never stored.
https://cloudpos.pk by default. Use a real HTTPS address; use a test user, not your owner account, when demonstrating to others.—Security model
| Protection | How it works |
|---|---|
| Two credentials | The API key identifies the application; the bearer token identifies the logged-in CloudPOS user. Both are required on every call. A token only works together with the key it was issued for. |
| Passwords & tokens | Tokens are random 256-bit values and only their SHA-256 hash is stored. Changing the user’s password, disabling the user or logging out invalidates tokens immediately. Refresh tokens rotate on every use; replaying an old one revokes the whole session. |
| Login lockout | 5 wrong passwords from one IP in 10 minutes lock that IP out of login (429 login_locked with the seconds to wait). 20 wrong passwords against one account from any IPs pause API login for that account. |
| Automatic IP blocking | Bad API keys, bad tokens, bad logins and rate-limit abuse are strikes. 10 strikes in 15 minutes block the IP (403 ip_blocked): 15 min, then 1 h, 6 h, 24 h for repeat offenders. Owners can also set a per-key IP allow-list and a global allow-list. |
| Rate limits | 120 requests/min per IP, 300/min per token, 60 writes/min per token, 10 token requests/min per IP. Responses carry X-RateLimit-Limit, X-RateLimit-Remaining and Retry-After. |
| Authorization | The user’s group permissions apply exactly as in the admin panel (Admin accounts cannot delete, as in the panel). Warehouse, biller and “own records only” restrictions are enforced; a warehouse-bound API key limits data to that warehouse. |
| Input hardening | Only whitelisted columns can be written (ids, group, balances and other system columns are read-only; unknown fields are rejected with 422), all queries are parameterised, filters and sort columns are whitelisted, bodies are limited to 1 MB JSON. |
| Transport & headers | HTTPS required, strict CORS allow-list (no cookies are ever used), Cache-Control: no-store, nosniff, HSTS and a locked-down CSP on every response. No stack traces or SQL errors are ever returned. |
| 2FA | Accounts with authenticator-app 2FA send the 6-digit code (or a recovery code) as otp. Accounts using e-mailed one-time codes cannot use the API until authenticator 2FA is set up. Codes cannot be replayed. |
| Audit trail | Every request is logged (time, IP, key, user, method, path, status, duration — never passwords, tokens or bodies). |
Conventions
- Success:
{"success":true,"data":...,"meta":{"page","per_page","total","pages"}}. Error:{"success":false,"error":{"code","message","retry_after?"}}. - Lists:
page,per_page(max 100),q(search),sort=-id,fields=id,name,expand=items. Filter any column with?city=Lahoreor?grand_total__gte=1000(__ne __gt __gte __lt __lte __like __in __null). GET /api/v2/<resource>/_schemareturns the live columns of your installation: type, nullable, writable, required.PUTis an alias ofPATCH(partial update).POSTreturns201and aLocationheader.- Records that other documents depend on answer
409 in_useon delete (for example a customer with sales). - Sales, purchases, quotes, transfers, adjustments, payments, expenses, deposits and stock are read-only in v2: they must pass through the accounting engine (stock, costing and ledger) and are posted from the POS/admin or the v1 mobile APIs.
Status and error codes
| HTTP | code | Meaning |
|---|---|---|
| 400 | https_required, bad_json, unknown_filter, bad_id | Malformed request |
| 401 | invalid_api_key, token_required, invalid_token, invalid_credentials, otp_required, invalid_otp, invalid_refresh_token | Missing or wrong credentials |
| 403 | forbidden, ip_blocked, ip_not_allowed, not_allowed, two_factor_unsupported | Authenticated but not allowed / IP blocked |
| 404 / 405 / 409 | not_found, method_not_allowed, in_use | Unknown record or method; delete blocked |
| 413 / 415 / 422 | payload_too_large, unsupported_media_type, unknown_fields, read_only_fields, missing_fields, invalid_field | Body rejected |
| 429 | rate_limited, login_locked | Slow down; see Retry-After |
| 503 | api_disabled | API feature switched off for the account |
Endpoint reference
Loading the OpenAPI specification…
Import cloudpos-openapi-v2.json into Postman, Insomnia, Swagger Editor or any OpenAPI code generator. Your own installation also serves it live (with your exact columns) at /api/v2/openapi.json.