API Documentation
REST API for external integration. Access articles, stock, orders, receptions and more via Bearer token.
Overview
The API allows external systems (ERP, mobile apps) to read data from 3PL Client. Authentication uses Bearer tokens (Laravel Sanctum). All data endpoints require authentication.
Base URL: https://flowscmc.eu/api
Machine-readable OpenAPI 3.0 specification (paths aligned with this API): https://flowscmc.eu/openapi.json
Authentication
Obtain a Bearer token by sending email and password:
POST https://flowscmc.eu/api/auth/token
Content-Type: application/json
{
"email": "your@email.com",
"password": "your-password"
}
// Response:
{
"token": "1|abc123...",
"user": { "id": 1, "name": "...", "email": "..." }
}
Use the token in all subsequent requests:
Authorization: Bearer 1|abc123...
To revoke the current token (logout):
POST https://flowscmc.eu/api/auth/revoke
Authorization: Bearer 1|abc123...
Company context
To filter data by company, send the optional header:
X-Company-Id: 123
The user must have access to the specified company. Without this header, super-admins see all companies; regular users see their primary company.
UM 3PL quantities on order lines
When defining an article, the first unit of measure in the system (field um3pl, UM 3PL in the UI) must be the one used for physical warehouse handling. UM2 and UM3 are for higher packaging levels when needed.
Purchase orders, sales orders, receptions, and returns use line fields um3pl and quantity_um3pl. You may send decimals with a comma (e.g. 1,5); the API normalizes to a dot before validation.
If the article requires whole-number UM 3PL quantities, or the 3PL stock-unit catalog marks that UM code as integer-only, quantity_um3pl must be a whole number. Otherwise validation fails with the standard error payload.
eTSM inbound (shared Bearer, not Sanctum)
Configure ETSM_INBOUND_BEARER_TOKEN in the environment. Use Authorization: Bearer <that token>. For creating receptions, call POST /api/integrations/etsm/receptions with the same JSON body as POST /api/receptions and header X-Company-Id set to the client company id. GET /api/integrations/etsm/ping verifies the token.
GET https://flowscmc.eu/api/integrations/etsm/ping
Authorization: Bearer <ETSM_INBOUND_BEARER_TOKEN>
POST https://flowscmc.eu/api/integrations/etsm/receptions
Authorization: Bearer <ETSM_INBOUND_BEARER_TOKEN>
X-Company-Id: 123
Content-Type: application/json
{ ... same JSON as POST /api/receptions ... }
Pagination
List endpoints support pagination via query parameters:
?page=1&per_page=25
Default per_page: 25. Maximum per_page: 100 (200 for stock). Response includes meta and links.
Available endpoints
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/health |
Health check for monitoring (no auth required) |
GET |
/api/integrations/etsm/ping |
eTSM connectivity check (shared Bearer; 503 if token not configured) |
POST |
/api/integrations/etsm/receptions |
Create reception from eTSM (X-Company-Id required; same rules as /api/receptions) |
GET |
/api/articles |
List articles (paginated) |
GET |
/api/articles/{id} |
Article details |
GET |
/api/stock |
Stock levels (paginated, max 200/page) |
GET |
/api/sales-orders |
Sales orders (paginated) |
GET |
/api/sales-orders/{id} |
Sales order details |
GET |
/api/purchase-orders |
Purchase orders (paginated) |
GET |
/api/purchase-orders/{id} |
Purchase order details |
GET |
/api/receptions |
Receptions (paginated) |
GET |
/api/receptions/{id} |
Reception details |
GET |
/api/returns |
Returns (limit 100) |
GET |
/api/returns/{id} |
Return details |
GET |
/api/webhooks |
Webhooks list |
GET |
/api/webhooks/{id} |
Webhook details |
GET |
/graphql |
GraphQL endpoint – Query articles and other data via GraphQL. Requires Bearer token and X-Company-Id header. |
GraphQL endpoint
Query articles and other data via GraphQL. Requires Bearer token and X-Company-Id header.
Base URL: https://flowscmc.eu/graphql
Example query – list articles:
POST https://flowscmc.eu/graphql
Authorization: Bearer YOUR_TOKEN
X-Company-Id: 1
Content-Type: application/json
{
"query": "{ articles(limit: 10) { id article_code description } }"
}
Use the same Bearer token and X-Company-Id header as for REST endpoints.
Health check (JSON)
GET /api/health returns the same JSON as GET /health and GET /up (no auth). The body includes aggregate checks, heartbeats (per scheduler name, last ping, ok), integrations and modules. If the heartbeats table is empty, items contains a placeholder row for cron and no_records is true until the scheduler runs heartbeat:ping.
{
"status": "healthy",
"app": { "name": "3PL", "env": "production" },
"urls": {
"app": "https://example.com",
"api": "https://example.com/api"
},
"checks": {
"database": true,
"cache": true,
"queue": true,
"redis": true,
"storage": true,
"storage_public": true,
"heartbeat": true
},
"heartbeats": {
"stale_after_minutes": 15,
"no_records": false,
"items": [
{ "name": "cron", "last_ping_at": "2026-04-09T12:00:00.123456Z", "last_ping_at_ms": 1775736000123, "ok": true }
]
},
"integrations": { "anaf": true },
"modules": [ { "slug": "api", "name": "API" } ],
"timestamp": "2026-04-09T12:00:00+00:00"
}
urls.app and urls.api come from APP_URL (base app and /api). Prometheus: append ?format=prometheus. Web UI with live heartbeats: Platform → Health (super-admin).
Example request
curl -X GET "https://flowscmc.eu/api/articles" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-Company-Id: 1" \
-H "Accept: application/json"
Rate limiting
POST /api/auth/token: 10 requests per minute- Data endpoints: 60 requests per minute
API Playground
Test API endpoints directly from this page. First obtain a token, then select an endpoint and send the request.