Version: 1.0.0
Last Updated: March 19, 2025
Documentation: https://docs.onescp.com
http://api.onescp.com — use this base URL for API requests.---
1. Overview
2. Authentication
3. Core APIs
- Orders
- Shipments
- Items
- Tasks
4. Supporting APIs
- Suppliers
- Carriers
5. Webhooks
6. Sync/Delta APIs
7. Sync from ERP to Portal
8. ERP Integration Checklist
9. Error Handling
10. Rate Limiting
11. Best Practices
12. Support
13. Infrastructure & Requirements
---
This API documentation is designed for third-party ERP systems to integrate with the ONESCP Portal. The API provides endpoints for managing Orders, Shipments, Items, and Tasks with full CRUD operations, filtering, pagination, and document management.
Currently, the API is at version 1.0.0. All endpoints are under /api/ prefix.
All API responses follow a consistent format:
Success Response:
{
"success": true,
"data": { ... },
"message": "Operation successful"
}
Error Response:
{
"success": false,
"message": "Error description",
"error": "Detailed error information"
}
---
All API endpoints (except authentication endpoints) require a valid JWT token in the Authorization header.
Endpoint: POST /api/auth/login
Request:
{
"email": "user@example.com",
"password": "your_password"
}
Response:
{
"success": true,
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"_id": "user_id",
"name": "John Doe",
"email": "user@example.com",
"role": "buyer",
"companyId": "company_id"
}
}
Include the token in the Authorization header for all subsequent requests:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
POST /api/auth/refresh (if implemented)For ERP integrations, API key authentication will be available as an alternative to user-based JWT tokens.
---
Orders represent purchase orders in the supply chain system. Each order contains line items, supplier information, delivery schedules, and documents.
#### Base Endpoint/api/purchase-order
#### Get All Orders
Endpoint: GET /api/purchase-order/allOrders
Headers:
Authorization: Bearer {token}
Query Parameters:
page (optional): Page number (default: 1)limit (optional): Items per page (default: 10)status (optional): Filter by status (draft, pending, approved, rejected, completed)supplier (optional): Filter by supplier IDdateFrom (optional): Filter orders from date (ISO 8601)dateTo (optional): Filter orders until date (ISO 8601)Response:
{
"success": true,
"orders": [
{
"_id": "order_id",
"purchaseOrderNumber": "PO-2024-001",
"supplier": {
"name": "ABC Electronics",
"email": "contact@abcelectronics.com"
},
"status": "approved",
"priority": "p1",
"orderLines": [
{
"_id": "line_id",
"position": "10",
"item": {
"number": "ITEM-001",
"name": "Laptop Computer",
"unitPrice": 999.99
},
"quantity": 10,
"prices": {
"netPrice": 9999.90
}
}
],
"totalAmount": 9999.90,
"deliveryDate": "2024-12-31",
"createdAt": "2024-01-15T10:30:00Z",
"updatedAt": "2024-01-15T10:30:00Z"
}
],
"pagination": {
"page": 1,
"limit": 10,
"total": 25,
"pages": 3
}
}
#### Get Order by ID
Endpoint: GET /api/purchase-order/{id}
Response:
{
"success": true,
"order": {
"_id": "order_id",
"purchaseOrderNumber": "PO-2024-001",
"supplier": { ... },
"orderLines": [ ... ],
"documents": [ ... ],
"status": "approved",
"createdAt": "2024-01-15T10:30:00Z",
"updatedAt": "2024-01-15T10:30:00Z"
}
}
#### Create Order
Endpoint: POST /api/purchase-order/create
Request Body:
{
"supplier": {
"name": "ABC Electronics",
"email": "contact@abcelectronics.com",
"address": "123 Supplier St, City, Country"
},
"orderLines": [
{
"position": "10",
"item": {
"number": "ITEM-001",
"name": "Laptop Computer",
"unitPrice": 999.99,
"purchaseUnitOfMeasureIso": "EA"
},
"quantity": 10,
"prices": {
"netPrice": 9999.90
},
"description": "High-performance laptop"
}
],
"deliveryDate": "2024-12-31",
"priority": "p1",
"notes": "Urgent delivery required"
}
Response:
{
"success": true,
"message": "Purchase order created successfully",
"order": {
"_id": "new_order_id",
"purchaseOrderNumber": "PO-2024-002",
...
}
}
#### Update Order
Endpoint: PUT /api/purchase-order/{id}
Request Body:
{
"deliveryDate": "2025-01-15",
"notes": "Updated delivery notes",
"priority": "p2"
}
#### Update Order Status
Endpoint: PUT /api/purchase-order/{id}/status
Request Body:
{
"status": "approved",
"notes": "Approved by manager"
}
Status Values:
draft - Order is in draft statepending - Order is pending approvalapproved - Order is approvedrejected - Order is rejectedcompleted - Order is completed#### Delete Order
Endpoint: DELETE /api/purchase-order/{id}
Response:
{
"success": true,
"message": "Purchase order deleted successfully"
}
#### Order Line Management
Add Order Line:POST /api/purchase-order/{id}/lines
Update Order Line:PUT /api/purchase-order/{id}/lines/{lineId}
Delete Order Line:DELETE /api/purchase-order/{id}/lines/{lineId}
#### Order Documents
Add Document:POST /api/purchase-order/{id}/documents
Content-Type: multipart/form-data
Form Data:
document: File to uploadtype: Document type (Invoice, Shipping, Contract, General, Custom Clearance)name: Document name (optional)description: Document description (optional)Get Documents:GET /api/purchase-order/{id}/documents
Delete Document:DELETE /api/purchase-order/{id}/documents/{documentId}
---
Shipments represent the transportation of goods from origin to destination. Each shipment is linked to purchase order lines and can contain multiple containers.
#### Base Endpoint/api/shipment
#### Get All Shipments
Endpoint: GET /api/shipment
Query Parameters:
page (optional): Page numberlimit (optional): Items per pagestatus (optional): Filter by status (pending, in_transit, delivered, cancelled)carrier (optional): Filter by carrier nameResponse:
{
"success": true,
"shipments": [
{
"_id": "shipment_id",
"shipmentNumber": "SH-2024-001",
"purchaseOrder": "order_id",
"status": "in_transit",
"type": "Ocean",
"departureFrom": "Shanghai Port",
"finalDestination": "Los Angeles Port",
"carrier": "Maersk Line",
"containers": [
{
"_id": "container_id",
"containerNumber": "MSKU1234567",
"containerType": "40ft",
"status": "In Transit",
"eta": "2024-02-15T14:30:00Z"
}
],
"scheduledDeliveryDate": "2024-02-15",
"createdAt": "2024-01-15T10:30:00Z"
}
],
"pagination": { ... }
}
#### Get Shipment by ID
Endpoint: GET /api/shipment/{id}
#### Create Shipment
Endpoint: POST /api/shipment/purchase-orders/{purchaseOrderId}/lines/{lineId}
Request Body:
{
"departureFrom": "Shanghai Port",
"departureCity": "Shanghai",
"departureCountryISO2": "CN",
"finalDestination": "Los Angeles Port",
"finalDestinationCity": "Los Angeles",
"finalDestinationCountryISO2": "US",
"type": "Ocean",
"carrier": "Maersk Line",
"scheduledDeliveryDate": "2024-02-15",
"containers": [
{
"containerNumber": "MSKU1234567",
"containerType": "40ft",
"sealNumber": "SEAL123456",
"weight": 25000,
"volume": 67.7
}
]
}
#### Update Shipment
Endpoint: PATCH /api/shipment/{id}
Request Body:
{
"status": "in_transit",
"carrier": "CMA CGM",
"scheduledDeliveryDate": "2024-02-20"
}
#### Update Shipment Status
Endpoint: PATCH /api/shipment/{id}/status
Request Body:
{
"status": "delivered"
}
Status Values:
pending - Shipment is pendingin_transit - Shipment is in transitdelivered - Shipment is deliveredcancelled - Shipment is cancelled#### Container Management
Add Container:POST /api/shipment/{id}/containers
Update Container:PATCH /api/shipment/{id}/containers/{containerId}
Delete Container:DELETE /api/shipment/{id}/containers/{containerId}
#### Shipment Documents
Add Document:POST /api/shipment/{id}/documents
Get Documents:GET /api/shipment/{id}/documents
Delete Document:DELETE /api/shipment/{id}/documents/{documentId}
---
Items represent products or materials in the inventory system. Items can be of different types: Material, Supplier, or Attributes.
#### Base Endpoint/api/items
#### Get All Items
Endpoint: GET /api/items
Query Parameters:
page (optional): Page numberlimit (optional): Items per pagesearch (optional): Search by name or descriptioncategory (optional): Filter by categoryitemStatus (optional): Filter by status (Pending, Under Approval, Processed)Response:
{
"success": true,
"items": [
{
"_id": "item_id",
"itemNumber": "ITEM-001",
"name": "Laptop Computer",
"description": "High-performance laptop",
"category": "Electronics",
"type": "Material",
"itemStatus": "Processed",
"material": {
"MATNR": "000000000000015330",
"LAEDA": "10/29/2024",
"MTART": "120404"
},
"createdAt": "2024-01-15T10:30:00Z"
}
],
"pagination": { ... }
}
#### Get Item by ID
Endpoint: GET /api/items/{id}
#### Create Item
Endpoint: POST /api/items
Request Body:
{
"itemNumber": "ITEM-002",
"name": "Desktop Computer",
"description": "High-performance desktop",
"category": "Electronics",
"type": "Material",
"material": {
"MATNR": "000000000000015331",
"LAEDA": "10/29/2024",
"MTART": "120404"
}
}
#### Update Item
Endpoint: PUT /api/items/{id}
#### Delete Item
Endpoint: DELETE /api/items/{id}
#### Bulk Import Items
Endpoint: POST /api/items/bulk-import
Content-Type: multipart/form-data
Form Data:
file: CSV or Excel file containing itemsupdateExisting: Boolean (default: false)Response:
{
"success": true,
"message": "Items imported successfully",
"imported": 25,
"updated": 5,
"errors": []
}
#### Export Items
Endpoint: GET /api/items/export
Query Parameters:
format (optional): Export format (csv, excel)---
Tasks represent workflow items that require action, such as order approvals, shipment confirmations, etc.
#### Base Endpoint/api/task
#### Get All Tasks
Endpoint: GET /api/task/allTasks
Query Parameters:
page (optional): Page numberlimit (optional): Items per pagestatus (optional): Filter by status (Open, In Progress, Completed, Rejected)priority (optional): Filter by priority (p1, p2, p3)Response:
{
"success": true,
"tasks": [
{
"_id": "task_id",
"title": "Review Purchase Order",
"description": "Review and approve purchase order PO-001",
"status": "Open",
"priority": "p1",
"assignedTo": {
"_id": "user_id",
"name": "John Doe",
"email": "john@example.com"
},
"relatedOrder": {
"_id": "order_id",
"purchaseOrderNumber": "PO-2024-001"
},
"dueDate": "2024-12-31T23:59:59Z",
"createdAt": "2024-01-15T10:30:00Z"
}
],
"pagination": { ... }
}
#### Get Task by ID
Endpoint: GET /api/task/taskid/{id}
#### Create Task
Endpoint: POST /api/task/{orderId}
Request Body:
{
"title": "Review Purchase Order",
"description": "Review and approve purchase order",
"assignedTo": "user_id",
"priority": "p1",
"dueDate": "2024-12-31T23:59:59Z"
}
#### Update Task
Endpoint: PUT /api/task/taskid/{id}
#### Accept or Reject Task
Endpoint: PUT /api/task/{id}/decision
Request Body:
{
"decision": "accept",
"comments": "Approved after review"
}
Decision Values:
accept - Accept the taskreject - Reject the task#### Update Task Status
Endpoint: PUT /api/task/taskid/{id}
Request Body:
{
"status": "In Progress"
}
Status Values:
Open - Task is openIn Progress - Task is in progressCompleted - Task is completedRejected - Task is rejected---
Suppliers represent vendor companies in the system. These endpoints are read-only for reference purposes.
#### Base Endpoint/api/suppliers
#### Get All Suppliers
Endpoint: GET /api/suppliers
Response:
{
"success": true,
"suppliers": [
{
"_id": "supplier_id",
"name": "ABC Electronics",
"email": "contact@abcelectronics.com",
"address": "123 Supplier St",
"phone": "+1234567890"
}
]
}
---
Carriers represent shipping companies. These endpoints are read-only for reference purposes.
#### Base Endpoint/api/carriers
#### Get All Carriers
Endpoint: GET /api/carriers
Response:
{
"success": true,
"carriers": [
{
"_id": "carrier_id",
"name": "Maersk Line",
"code": "MAEU",
"type": "Ocean"
}
]
}
---
Webhooks send HTTP POST requests to your URL when data changes, so your ERP can stay in sync in real time.
| Method | Endpoint | Description |
|--------|----------|-------------|
| POST | /api/webhooks/subscriptions | Create a subscription |
| GET | /api/webhooks/subscriptions | List your company’s subscriptions |
| GET | /api/webhooks/subscriptions/:id | Get one subscription |
| DELETE | /api/webhooks/subscriptions/:id | Delete a subscription |
POST /api/webhooks/subscriptions
Body:
https://your-erp.com/webhooks/onescp).Response: { "success": true, "subscription": { "_id", "url", "events", "status", ... } } (secret is not returned after creation).
| Event | When it is sent |
|-------|------------------|
| order.created | New order created |
| order.updated | Order updated |
| order.deleted | Order soft-deleted (after approval) |
| order.status_changed | Order status updated |
| shipment.created | New shipment created |
| shipment.updated | Shipment updated |
| shipment.deleted | Shipment soft-deleted (after approval) |
| shipment.status_changed | Shipment status updated |
| item.created | New item created |
| item.updated | Item updated |
| item.deleted | Item deleted or soft-deleted |
| task.created | New task created |
| task.updated | Task updated |
| task.completed | Task accepted/completed |
| task.rejected | Task rejected |
Each delivery is a POST to your url with:
Headers:
Content-Type: application/jsonX-Webhook-Signature: sha256= — verify with your secretX-Webhook-Event: X-Webhook-Delivery-Id: Body:
{
"event": "order.updated",
"timestamp": "2025-01-26T12:00:00.000Z",
"data": { "_id": "...", "purchaseOrderNumber": "PO-2024-001", "status": "approved", ... }
}
Compute HMAC-SHA256(secret, rawRequestBody) and compare to the X-Webhook-Signature value (without the sha256= prefix). If they match, the payload is from ONESCP.
Subscriptions are per company. You only receive events for data your company can access (e.g. orders where your company is buyer or supplier). Item events are sent to all subscribers (items are not company-scoped).
Deliveries are logged (success/failure, status code, duration). Your endpoint should return 2xx quickly; process the payload asynchronously if needed. Failed deliveries are logged for debugging.
---
Sync/Delta APIs return only records that changed since a given timestamp, for efficient incremental sync with ERPs.
All require Authorization: Bearer {token}.
| Entity | Method | Endpoint |
|----------|--------|----------|
| Orders | GET | /api/purchase-order/sync |
| Shipments| GET | /api/shipment/sync |
| Items | GET | /api/items/sync |
| Tasks | GET | /api/task/sync |
since (required): ISO 8601 timestamp (e.g. 2025-01-01T00:00:00Z). Only records with updatedAt (or deletedAt for soft-deletes) after this time are returned. Use a very old date or omit for initial full sync.page (optional): Page number, default 1.limit (optional): Items per page, default 100, max 500.Example: GET /api/purchase-order/sync?since=2025-01-25T00:00:00Z&page=1&limit=100
{
"success": true,
"created": [ { "_id": "...", "purchaseOrderNumber": "PO-2024-002", "createdAt": "...", ... } ],
"updated": [ { "_id": "...", "purchaseOrderNumber": "PO-2024-001", "status": "approved", "updatedAt": "...", ... } ],
"deleted": [ { "_id": "...", "deletedAt": "2024-01-16T12:00:00Z" } ],
"lastSyncTimestamp": "2024-01-16T12:00:00Z",
"hasMore": false,
"pagination": { "page": 1, "limit": 100, "total": 42 }
}
since.since (and created before or at since).deletedAt after since (IDs only plus deletedAt).since value for the next sync.since and next page.assignedTo is the current user.1. Initial sync: Call with since=1970-01-01T00:00:00Z (or omit) and page through until hasMore is false.
2. Incremental sync: Store lastSyncTimestamp from the last response; use it as since on the next run.
3. Conflict resolution: Use updatedAt (and deletedAt) to order and deduplicate on the client.
---
These endpoints let SAP or any ERP push data into the portal (ERP → portal). Use the same Authorization: Bearer {token} (e.g. a dedicated integration user). Upserts are idempotent: use erpId or business keys so the same payload does not create duplicates.
| Entity | Method | Endpoint |
|-----------|--------|----------|
| Orders | POST | /api/purchase-order/sync-from-erp |
| Shipments | POST | /api/shipment/sync-from-erp |
| Items | POST | /api/items/sync-from-erp |
{ "orders": [ { "erpId": "SAP-PO-123", "purchaseOrderNumber": "PO-001", "buyerCompany": "", "supplierCompany": "", "supplierId": "", "createdBy": "", ... } ] } erpId, or by purchaseOrderNumber + buyerCompany. New orders require purchaseOrderNumber, supplierCompany, supplierId, and createdBy (or the authenticated user is used as createdBy).{ "shipments": [ { "erpId": "SAP-SHP-456", "shipmentNumber": "SHP-001", "purchaseOrder": "", "lineIds": [ "" ], ... } ] } erpId, or by shipmentNumber + purchaseOrder. New shipments require purchaseOrder and lineIds.{ "items": [ { "itemNumber": "MAT-001", "name": "...", "type": "Material", ... } ] } itemNumber (unique). New items require itemNumber.{
"success": true,
"created": [ { "_id": "...", ... } ],
"updated": [ { "_id": "...", ... } ],
"errors": [ { "payload": { ... }, "message": "..." } ]
}
---
Use this checklist before sending Purchase Orders (and related data) from SAP/any ERP to ONESCP to avoid common 400 Bad Request validation errors.
"1001") in fields that expect ONESCP IDs.supplierCompany must be the ONESCP Company _id (MongoDB ObjectId).supplierId must be the ONESCP User _id (MongoDB ObjectId) for the supplier contact user.vendorNumber → ONESCP supplierCompany _id (+ optionally ONESCP supplierId).purchaseOrderNumber (string)supplierCompany (ONESCP Company _id)supplierId (ONESCP User _id)supplierAccountNumber (string)destination (object): delivery address (at minimum country/city/postal code/address lines)contactEmail (string): buyer contact email (must not be empty)lines (array): order lines (note: use lines, not orderLines)lines, not orderLines.contactEmail: "").erpId where possible for idempotent upserts.---
200 OK - Request successful201 Created - Resource created successfully400 Bad Request - Invalid request parameters401 Unauthorized - Authentication required or invalid token403 Forbidden - Insufficient permissions404 Not Found - Resource not found409 Conflict - Resource conflict (e.g., duplicate entry)422 Unprocessable Entity - Validation error500 Internal Server Error - Server error{
"success": false,
"message": "Error description",
"error": {
"code": "ERROR_CODE",
"details": "Detailed error information",
"field": "field_name" // If validation error
},
"timestamp": "2024-01-15T10:30:00Z"
}
AUTH_REQUIRED - Authentication token requiredAUTH_INVALID - Invalid or expired tokenVALIDATION_ERROR - Request validation failedNOT_FOUND - Resource not foundDUPLICATE_ENTRY - Duplicate resourcePERMISSION_DENIED - Insufficient permissionsSERVER_ERROR - Internal server error---
Rate limiting is implemented to ensure fair usage and system stability.
Response headers include rate limit information:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1642248000
When rate limit is exceeded, the API returns:
Status Code: 429 Too Many Requests
Response:
{
"success": false,
"message": "Rate limit exceeded",
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"retryAfter": 60
}
}
---
success field in responsescreatedAt, updatedAt) for change tracking---
/api-docs endpoint (e.g. https://api.onescp.com/api-docs).*For deployment: point the domain docs.onescp.com at the docs server and map / to the full doc and /quick-start to the quick start page (e.g. proxy to backend /docs and /docs/quick-start).*
Version 1.0.0 (January 2025)
Upcoming
---
All dates are in ISO 8601 format: YYYY-MM-DDTHH:mm:ssZ
Example: 2024-01-15T10:30:00Z
All timestamps are in UTC (Coordinated Universal Time).
camelCase for field namesp1, p2, p3)Pagination is 1-indexed (first page is page 1).
---
This section describes deployment options and technical requirements for running ONESCP on a dedicated secured server (physical or VPS) or in the cloud. Use it when a customer wants to self-host or when you need hardware and license guidance.
| Option | Description |
|--------|--------------|
| Option 1 | Physical server or VPS — Windows Server (on-premises or hosted VPS) |
| Option 2 | Physical server or VPS — Linux (recommended for on-prem / VPS) |
| Option 3 | Amazon Web Services (AWS) — cloud-hosted (EC2 + managed or self-managed database) |
---
---
---
---
| Component | Purpose |
|----------|---------|
| Node.js (LTS, e.g. v20) | Application runtime |
| Nginx or IIS (Windows) | Reverse proxy / HTTPS |
| MongoDB | Primary database |
| Redis | Email queue and caching (recommended on Linux; optional on Windows) |
---
---
| Environment | vCPUs | RAM | Storage | Use case |
|-------------|-------|-----|---------|----------|
| Small / pilot | 4 | 8–16 GB | 200–300 GB SSD | Single company, low volume |
| Medium | 4–8 | 16–32 GB | 300–500 GB SSD | Multiple companies or higher volume |
| Large | 8+ | 32 GB+ | 500 GB+ SSD / scaled DB | High volume, separate DB server recommended |
For production, backups, monitoring, and security hardening (firewall, SSL, OS updates) are the responsibility of the party operating the server (customer or partner).
---
Document Version: 1.0.0
Last Updated: March 19, 2025
For: Third-Party ERP Integration