Sapientia ERP
Developers
A plain JSON API over HTTPS. Create a key under Settings → API keys in the app, choose its scopes and optionally bind it to one company. Keys look like sk_live_erp_… (or sk_test_erp_… for test keys, which are accepted but flagged).
Authentication
curl https://erp.sapientiainformationsolutions.com/api/v1/companies \ -H "Authorization: Bearer sk_live_erp_…"
Every response is { "data": … } or { "error": { "code", "message" } }. Codes: unauthenticated (401), forbidden (403, missing scope or wrong company), not_found, invalid_request (400/422), query_failed (500). Dates are YYYY-MM-DD; timestamps ISO 8601; money is PHP with two decimals.
Scopes
journals:read· read journals and linesjournals:write· create and transition journalsaccounts:read· companies and chart of accountsreports:read· trial balance and other reportspostings:write· daily summary and shift-close feedswebhooks:manage· subscriptionstickets:write· open helpdesk ticketsorders:write· push and ship channel ordersorders:read· list channel ordersitems:read· catalogue with price and stock
Idempotency
Daily summaries are keyed by company + app + date; channel orders by channel + external_id; tickets by channel + external_ref; journals accept an idempotency_key. Re-sending returns the original with replayed: true and HTTP 200.
Companies and accounts
/api/v1/companiesscope accounts:readCompanies the key can post to.
{ "data": [{ "id", "name", "tin", "base_currency" }] }/api/v1/accountsscope accounts:readChart of accounts of a company.
Query: company (required unless the key is bound to one)
Journals
/api/v1/journalsscope journals:readList journals.
Query: company · status=draft|submitted|posted|cancelled · from, to (posting_date) · limit (≤500)
/api/v1/journalsscope journals:writeCreate a journal (draft, or posted when post=true and the key may post).
{ "company": "<uuid>", "posting_date": "2026-10-12", "memo": "…", "reference": "…", "idempotency_key": "…", "post": true, "lines": [{ "account": "1010", "debit": 1000 }, { "account": "4010", "credit": 1000, "memo": "…" }] }/api/v1/journals/{id}scope journals:readOne journal with lines.
/api/v1/journals/{id}/transitionscope journals:writeMove a journal through its workflow.
{ "action": "submit" | "post" | "reverse", "note": "…" }App feeds (postings)
/api/v1/postings/daily-summaryscope postings:writeOne call per business day: movements by bucket become one posted journal through the company's mapping; balances are kept for the sub-ledger report. Same day twice returns the same journal.
{ "company": "<uuid>", "app": "sugoa_daily", "date": "2026-10-11", "movements": { "sales": 12500, "fees": 1250, "payouts": 9800 }, "balances": { "escrow_held": 431, "wallet_balances": 3500 } }/api/v1/postings/shift-closescope postings:writePOS shift close: sales by payment method, discounts, tips and cash drawer variance posted as one journal.
Orders and catalogue (e-commerce)
/api/v1/ordersscope orders:writePush a shop order to a sales channel. Deduped on channel + external_id (replayed: true). Becomes customer, sales order, invoice and receipt per the channel's settings.
{ "company": "<uuid>", "channel": "shopify", "order": { "external_id": "1001", "number": "#1001", "ordered_at": "2026-10-12T10:00:00+08:00", "customer": { "name": "Ana Cruz", "email": "ana@example.com", "phone": "0917…" }, "ship_to": "12 Mango Ave, Cebu City", "payment_method": "gcash", "paid": true, "discount": 50, "shipping_fee": 80, "platform_fee": 0, "lines": [{ "sku": "BEANS-250", "name": "House blend 250g", "qty": 2, "unit_price": 450 }] } }{ "data": { "channel_order_id", "status": "invoiced", "sales_order_id", "invoice_id", "payment_id", "total", "warning" }, "replayed": false } (422 with status "failed" and error when a SKU is unknown)/api/v1/ordersscope orders:readList channel orders.
Query: company · channel (key) · status · from · limit
/api/v1/orders/{id}scope orders:readOne channel order with its raw payload and links.
/api/v1/orders/{id}/shipscope orders:writeMark shipped; creates the shipment (and the delivery when stock has not left yet).
{ "tracking_no": "JT123", "carrier": "J&T Express" }/api/v1/itemsscope items:readCatalogue for a storefront: sku, barcode, name, price (party price list when party is given), stock on hand.
Query: company · party (optional customer id for its price list) · updated_since (ISO timestamp)
Support
/api/v1/ticketsscope tickets:writeOpen a helpdesk ticket from an app. Same external_ref returns the existing ticket.
{ "company": "<uuid>", "subject": "Order late", "body": "…", "priority": "high", "channel": "api", "external_ref": "sugoa-ord-77", "contact": { "name", "email", "phone" }, "category": "Delivery", "tags": ["sugoa"] }Reports
/api/v1/reports/trial-balancescope reports:readTrial balance for a range.
Query: company · from · to
Webhooks
/api/v1/webhooksscope webhooks:manageYour subscriptions.
/api/v1/webhooksscope webhooks:manageSubscribe a URL to events. Deliveries are signed with HMAC-SHA256 of the body using the subscription secret (header X-Sapientia-Signature) and retried with back-off.
{ "url": "https://example.com/hook", "events": ["journal.posted", "order.received", "order.shipped", "order.cancelled"], "description": "…" }/api/v1/webhooks/{id}scope webhooks:manageRemove a subscription.
Webhook events
journal.posted, order.received, order.shipped, order.cancelled. Each delivery is a POST with JSON { "event", "payload", "delivered_at" }; verify X-Sapientia-Signature = hex HMAC-SHA256(body, secret). Deliveries retry every 5 minutes with back-off for a day.