Endpoints
| Method | Path | Description |
|---|---|---|
GET | /api/v1/suppliers | List suppliers (paginated + filtered) |
GET | /api/v1/suppliers/{id} | Get a single supplier |
POST | /api/v1/suppliers | Create a new supplier |
PATCH | /api/v1/suppliers/{id} | Partially update a supplier |
DELETE | /api/v1/suppliers/{id} | Delete a supplier |
POST | /api/v1/suppliers/bulk | Bulk create/update suppliers |
GET /api/v1/suppliers
Note
Default page size is 50 (max 250). Supports query parameters: complianceStatus, search, sortBy, sortOrder.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
page | integer | 0 | Zero-based page index |
size | integer | 50 | Items per page (max 250) |
country | string | — | ISO alpha-2 country filter |
category | string | — | Category filter |
complianceStatus | string | — | Compliance status filter |
search | string | — | Free-text search on name/category |
sortBy | string | created_date | Sort field |
sortOrder | string | desc | asc or desc |
Shell
curl "http://localhost:8080/api/v1/suppliers"curl "http://localhost:8080/api/v1/suppliers?country=IT&category=TEXTILES&sortBy=name&sortOrder=asc&size=100"curl "http://localhost:8080/api/v1/suppliers?search=acme&size=20"
JavaScript
const resp = await fetch('/api/v1/suppliers?country=IT&sortBy=name&sortOrder=asc');const { items, total, page, page_size } = await resp.json();
Response 200 OK
JSON
{"items": [{"id": 1,"name": "Acme Textiles Ltd","category": "TEXTILES","address": "Via Roma 12","city": "Milano","zip_code": "20100","province": "MI","country": "IT","latitude": 45.4642,"longitude": 9.1900,"contact_name": "Mario Rossi","contact_email": "mario@acme.it","reach_compliant": true,"svhc_compliant": false,"activity_type": "Dyeing","metadata": { "erp_code": "SUP-042" },"created_at": "2025-09-01T10:00:00","updated_at": "2025-09-01T10:00:00"}],"total": 23,"page": 0,"page_size": 50}
POST /api/v1/suppliers
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | ✅ | Supplier legal name |
category | string | ✅ | Business category |
custom_category | string | ❌ | Custom description when category is "Altro" |
address | string | ❌ | Street address |
city | string | ❌ | City |
zip_code | string | ❌ | Postal code (CAP) |
province | string | ❌ | Province/Region |
country | string | ❌ | ISO 3166-1 alpha-2 |
latitude | number | ❌ | Geographic latitude |
longitude | number | ❌ | Geographic longitude |
contact_name | string | ❌ | Contact person name |
contact_email | string | ❌ | Contact email |
contact_phone | string | ❌ | Contact phone |
reach_compliant | boolean | ❌ | Default: false |
svhc_compliant | boolean | ❌ | Default: false |
activity_type | string | ❌ | Type of supplier activity |
metadata | object | ❌ | Arbitrary JSON key-value pairs |
Shell
curl -X POST http://localhost:8080/api/v1/suppliers \-H "Content-Type: application/json" \-d '{"name": "Acme Textiles Ltd","category": "TEXTILES","address": "Via Roma 12","city": "Milano","zip_code": "20100","province": "MI","country": "IT","latitude": 45.4642,"longitude": 9.1900,"contact_name": "Mario Rossi","contact_email": "mario@acme.it","reach_compliant": true,"activity_type": "Dyeing","metadata": { "erp_code": "SUP-042" }}'
JavaScript
const resp = await fetch('/api/v1/suppliers', {method: 'POST',headers: { 'Content-Type': 'application/json' },body: JSON.stringify({name: 'Acme Textiles Ltd',category: 'TEXTILES',country: 'IT',city: 'Milano',reach_compliant: true,metadata: { erp_code: 'SUP-042' }})});
DELETE /api/v1/suppliers/{id}
Hard-deletes the supplier and cascades to all associated certifications.
Shell
curl -X DELETE http://localhost:8080/api/v1/suppliers/1
Response: 204 No Content
POST /api/v1/suppliers/bulk
Upserts by name. Returns aggregated counts.
JSON
{"items": [{ "name": "Acme Textiles", "country": "IT", "category": "TEXTILES" },{ "name": "Delta Chemicals", "country": "DE", "category": "CHEMICALS" }]}
Response:
JSON
{ "created": 1, "updated": 1, "failed": 0, "errors": [] }