Kobo PLM API Documentation
The Kobo PLM API provides programmatic access to your product lifecycle management data. Use it to integrate with ERPs, build custom workflows, or sync data with external systems.
Base URL
All API requests must be made over HTTPS. Calls made over plain HTTP will fail. API requests without authentication will also fail.
Authentication
All API requests require authentication using an API key. Include your API key in theX-API-Key header with every request.
curl -X GET "https://api.koboplm.com/api/v1/styles" \
-H "X-API-Key: your_api_key_here" \
-H "Content-Type: application/json"Getting an API Key
- Log in to Kobo PLM
- Go to Account Settings → API Keys
- Click Create API Key
- Select the scopes (permissions) you need
- Copy and securely store your key - it won't be shown again
API Key Scopes
| Scope | Description |
|---|---|
* | Full access to all resources |
styles:read | Read styles/products |
styles:write | Create, update, delete styles |
components:read | Read components/materials |
components:write | Create, update, delete components |
suppliers:read | Read suppliers |
suppliers:write | Create, update, delete suppliers |
purchase_orders:read | Read purchase orders |
purchase_orders:write | Create, update, delete purchase orders |
inventory:read | Read inventory levels |
inventory:write | Update inventory |
customers:read | Read customers |
customers:write | Create, update, delete customers |
sales_orders:read | Read sales orders |
sales_orders:write | Create, update, delete sales orders |
deliveries:read | Read deliveries |
webhooks:read | Read webhook configurations |
webhooks:write | Manage webhooks |
Rate Limiting
API requests are rate limited based on your subscription tier:
| Tier | Requests per Minute |
|---|---|
| Basic | 100 |
| Professional | 500 |
| Enterprise | 2,000 |
Rate limit headers are included in every response:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1699574400429 Too Many Requests response. Implement exponential backoff to handle this gracefully.Pagination
List endpoints return paginated results. Use these query parameters:
| Parameter | Type | Description |
|---|---|---|
page | integer | Page number (default: 1) |
per_page | integer | Items per page (default: 25, max: 100) |
Response includes pagination metadata:
{
"data": [...],
"meta": {
"current_page": 1,
"from": 1,
"last_page": 10,
"per_page": 25,
"to": 25,
"total": 250
},
"links": {
"first": "https://api.koboplm.com/api/v1/styles?page=1",
"last": "https://api.koboplm.com/api/v1/styles?page=10",
"prev": null,
"next": "https://api.koboplm.com/api/v1/styles?page=2"
}
}Filtering
Most list endpoints support filtering for incremental sync:
| Parameter | Type | Description |
|---|---|---|
updated_since | datetime | ISO 8601 datetime (e.g., 2024-01-01T00:00:00Z) |
created_since | datetime | ISO 8601 datetime (e.g., 2024-01-01T00:00:00Z) |
# Get styles updated in the last 24 hours
curl "https://api.koboplm.com/api/v1/styles?updated_since=2024-01-14T00:00:00Z" \
-H "X-API-Key: your_api_key"Error Handling
The API uses standard HTTP status codes:
| Code | Description |
|---|---|
| 200 | Success |
| 201 | Created |
| 204 | No Content (successful delete) |
| 400 | Bad Request - Invalid parameters |
| 401 | Unauthorized - Invalid or missing API key |
| 403 | Forbidden - Insufficient permissions |
| 404 | Not Found |
| 422 | Validation Error |
| 429 | Rate Limited |
| 500 | Server Error |
Error responses include details:
{
"message": "The given data was invalid.",
"errors": {
"name": ["The name field is required."],
"style_code": ["The style code has already been taken."]
}
}Styles
Styles represent your products/designs in Kobo PLM.
/stylesList all styles with optional filtering and pagination
/styles/{id}Get a specific style by ID
/stylesCreate a new style
/styles/{id}Update an existing style
/styles/{id}Delete a style
List Styles
| Parameter | Type | Description |
|---|---|---|
page | integer | Page number |
per_page | integer | Items per page (max 100) |
updated_since | datetime | Filter by update time |
created_since | datetime | Filter by creation time |
status | string | Filter by status |
season_id | integer | Filter by season |
Example Request
curl "https://api.koboplm.com/api/v1/styles?per_page=50&status=active" \
-H "X-API-Key: your_api_key"Example Response
{
"data": [
{
"id": 1,
"style_code": "SS24-001",
"name": "Classic Cotton Tee",
"description": "Premium cotton t-shirt",
"status": "active",
"category": {
"id": 1,
"name": "Tops"
},
"season": {
"id": 1,
"name": "Spring/Summer 2024"
},
"brand": {
"id": 1,
"name": "Main Brand"
},
"wholesale_price": "45.00",
"retail_price": "89.00",
"cost_price": "22.50",
"currency": "USD",
"sizes": ["XS", "S", "M", "L", "XL"],
"colors": [
{"id": 1, "name": "White", "hex": "#FFFFFF"},
{"id": 2, "name": "Black", "hex": "#000000"}
],
"images": [
{
"id": 1,
"url": "https://storage.koboplm.com/styles/1/main.jpg",
"type": "main"
}
],
"skus": [
{
"id": 1,
"sku": "SS24-001-WHT-S",
"size": "S",
"color": "White",
"barcode": "1234567890123"
}
],
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T14:45:00Z"
}
],
"meta": {
"current_page": 1,
"total": 150
}
}Create Style
curl -X POST "https://api.koboplm.com/api/v1/styles" \
-H "X-API-Key: your_api_key" \
-H "Content-Type: application/json" \
-d '{
"style_code": "SS24-002",
"name": "Slim Fit Chinos",
"description": "Modern slim fit chinos",
"category_id": 2,
"season_id": 1,
"status": "development",
"wholesale_price": 65.00,
"retail_price": 129.00,
"cost_price": 32.50,
"currency": "USD",
"sizes": ["28", "30", "32", "34", "36"]
}'Components
Components represent materials, trims, and other items used in production.
/componentsList all components
/components/{id}Get a specific component
/componentsCreate a new component
/components/{id}Update an existing component
/components/{id}Delete a component
List Components
| Parameter | Type | Description |
|---|---|---|
page | integer | Page number |
per_page | integer | Items per page |
updated_since | datetime | Filter by update time |
type | string | Filter by component type |
supplier_id | integer | Filter by supplier |
Example Response
{
"data": [
{
"id": 1,
"code": "FAB-001",
"name": "Organic Cotton Jersey",
"type": "fabric",
"description": "180gsm organic cotton jersey",
"supplier": {
"id": 1,
"name": "Premium Textiles Ltd"
},
"unit": "meter",
"unit_price": "8.50",
"currency": "USD",
"minimum_order_quantity": 100,
"lead_time_days": 14,
"specifications": {
"weight": "180gsm",
"width": "150cm",
"composition": "100% Organic Cotton"
},
"created_at": "2024-01-10T09:00:00Z",
"updated_at": "2024-01-12T11:30:00Z"
}
]
}Suppliers
/suppliersList all suppliers
/suppliers/{id}Get a specific supplier
/suppliersCreate a new supplier
/suppliers/{id}Update an existing supplier
/suppliers/{id}Delete a supplier
List Suppliers
| Parameter | Type | Description |
|---|---|---|
page | integer | Page number |
per_page | integer | Items per page |
updated_since | datetime | Filter by update time |
country | string | Filter by country code |
type | string | Filter by supplier type |
Example Response
{
"data": [
{
"id": 1,
"name": "Premium Textiles Ltd",
"code": "SUP-001",
"type": "manufacturer",
"email": "contact@premiumtextiles.com",
"phone": "+1-555-0100",
"website": "https://premiumtextiles.com",
"address": {
"street": "123 Industrial Way",
"city": "Los Angeles",
"state": "CA",
"postal_code": "90001",
"country": "US"
},
"contacts": [
{
"name": "John Smith",
"email": "john@premiumtextiles.com",
"phone": "+1-555-0101",
"role": "Sales Manager"
}
],
"payment_terms": "Net 30",
"currency": "USD",
"rating": 4.5,
"certifications": ["GOTS", "OEKO-TEX"],
"created_at": "2024-01-05T08:00:00Z",
"updated_at": "2024-01-14T16:20:00Z"
}
]
}Purchase Orders
/purchase-ordersList all purchase orders
/purchase-orders/{id}Get a specific purchase order
/purchase-ordersCreate a new purchase order
/purchase-orders/{id}Update an existing purchase order
/purchase-orders/{id}Delete a draft purchase order
Status Values
draft, pending,confirmed, in_production,shipped, delivered,cancelled
Example Response
{
"data": [
{
"id": 1,
"po_number": "PO-2024-0001",
"status": "confirmed",
"supplier": {
"id": 1,
"name": "Premium Textiles Ltd"
},
"order_date": "2024-01-15",
"expected_delivery_date": "2024-02-15",
"ship_to": {
"name": "Main Warehouse",
"address": "789 Warehouse Blvd, Chicago, IL 60601"
},
"currency": "USD",
"subtotal": "5000.00",
"tax": "0.00",
"shipping": "250.00",
"total": "5250.00",
"line_items": [
{
"id": 1,
"style": {
"id": 1,
"style_code": "SS24-001",
"name": "Classic Cotton Tee"
},
"sku": "SS24-001-WHT-M",
"size": "M",
"color": "White",
"quantity": 100,
"unit_price": "22.50",
"total": "2250.00"
}
],
"notes": "Rush order - priority shipping required",
"created_at": "2024-01-15T10:00:00Z",
"updated_at": "2024-01-15T14:30:00Z"
}
]
}Inventory
/inventoryList inventory items
/inventory/{id}Get a specific inventory item
/inventory/{id}Update inventory levels
/inventory/bulk-updateBulk update inventory
List Inventory
| Parameter | Type | Description |
|---|---|---|
page | integer | Page number |
per_page | integer | Items per page |
updated_since | datetime | Filter by update time |
style_id | integer | Filter by style |
location_id | integer | Filter by location |
low_stock | boolean | Filter low stock items |
Bulk Update Example
{
"updates": [
{
"sku": "SS24-001-WHT-M",
"location_id": 1,
"qty_on_hand": 175
},
{
"sku": "SS24-001-WHT-L",
"location_id": 1,
"qty_on_hand": 200
}
]
}Customers
/customersList all customers
/customers/{id}Get a specific customer
/customersCreate a new customer
/customers/{id}Update an existing customer
/customers/{id}Delete a customer
List Customers
| Parameter | Type | Description |
|---|---|---|
page | integer | Page number |
per_page | integer | Items per page |
updated_since | datetime | Filter by update time |
type | string | Filter by type (wholesale, retail) |
Sales Orders
/sales-ordersList all sales orders
/sales-orders/{id}Get a specific sales order
/sales-ordersCreate a new sales order
/sales-orders/{id}Update an existing sales order
/sales-orders/{id}Delete a sales order
Status Values
draft, pending,confirmed, processing,shipped, delivered,cancelled
Deliveries
Deliveries are read-only via the API.
/deliveriesList all deliveries
/deliveries/{id}Get a specific delivery
List Deliveries
| Parameter | Type | Description |
|---|---|---|
page | integer | Page number |
per_page | integer | Items per page |
updated_since | datetime | Filter by update time |
status | string | Filter by status |
purchase_order_id | integer | Filter by PO |
Webhooks
Webhooks allow you to receive real-time notifications when events occur in Kobo PLM. When you configure a webhook, Kobo PLM will send an HTTP POST request to your specified URL whenever the subscribed events occur.
Available Events
Style Events
| Event | Description |
|---|---|
style.created | A new style was created |
style.updated | A style was updated |
style.deleted | A style was deleted |
style.status_changed | A style's status changed |
Component Events
| Event | Description |
|---|---|
component.created | A new component was created |
component.updated | A component was updated |
component.deleted | A component was deleted |
Supplier Events
| Event | Description |
|---|---|
supplier.created | A new supplier was created |
supplier.updated | A supplier was updated |
supplier.deleted | A supplier was deleted |
Purchase Order Events
| Event | Description |
|---|---|
purchase_order.created | A new PO was created |
purchase_order.updated | A PO was updated |
purchase_order.status_changed | A PO's status changed |
purchase_order.confirmed | A PO was confirmed |
purchase_order.cancelled | A PO was cancelled |
Inventory Events
| Event | Description |
|---|---|
inventory.updated | Inventory levels changed |
inventory.low_stock | Inventory fell below reorder point |
Customer Events
| Event | Description |
|---|---|
customer.created | A new customer was created |
customer.updated | A customer was updated |
customer.deleted | A customer was deleted |
Sales Order Events
| Event | Description |
|---|---|
sales_order.created | A new sales order was created |
sales_order.updated | A sales order was updated |
sales_order.status_changed | A sales order's status changed |
Delivery Events
| Event | Description |
|---|---|
delivery.created | A new delivery was created |
delivery.checked_in | A delivery was received |
delivery.status_changed | A delivery's status changed |
Webhook Payload
All webhooks send a JSON payload with the following structure:
{
"event": "style.updated",
"created_at": "2024-01-15T14:30:00Z",
"data": {
"id": 1,
"type": "Style",
"attributes": {
"id": 1,
"style_code": "SS24-001",
"name": "Classic Cotton Tee",
"status": "active"
}
},
"meta": {
"api_version": "v1",
"change": {
"field": "status",
"previous_value": "development",
"new_value": "active"
}
}
}Webhook Headers
| Header | Description |
|---|---|
Content-Type | application/json |
User-Agent | KOBO-PLM-Webhooks/1.0 |
X-Webhook-Event | Event type (e.g., style.updated) |
X-Webhook-Event-Id | Unique event ID (UUID) |
X-Webhook-Timestamp | Unix timestamp |
X-Webhook-Signature | HMAC-SHA256 signature |
Signature Verification
To verify that a webhook came from Kobo PLM, validate the signature:
const crypto = require('crypto');
function verifyWebhookSignature(payload, signature, timestamp, secret) {
const signedPayload = `${timestamp}.${payload}`;
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(signedPayload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(`sha256=${expectedSignature}`)
);
}
// In your webhook handler:
app.post('/webhook', (req, res) => {
const signature = req.headers['x-webhook-signature'];
const timestamp = req.headers['x-webhook-timestamp'];
const payload = JSON.stringify(req.body);
if (!verifyWebhookSignature(payload, signature, timestamp, WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
// Process the webhook
console.log('Received event:', req.body.event);
res.status(200).send('OK');
});import hmac
import hashlib
def verify_webhook_signature(payload, signature, timestamp, secret):
signed_payload = f"{timestamp}.{payload}"
expected_signature = hmac.new(
secret.encode(),
signed_payload.encode(),
hashlib.sha256
).hexdigest()
return hmac.compare_digest(
signature,
f"sha256={expected_signature}"
)function verifyWebhookSignature($payload, $signature, $timestamp, $secret) {
$signedPayload = "{$timestamp}.{$payload}";
$expectedSignature = 'sha256=' . hash_hmac('sha256', $signedPayload, $secret);
return hash_equals($expectedSignature, $signature);
}Retry Policy
Failed webhook deliveries are automatically retried with exponential backoff:
| Attempt | Delay |
|---|---|
| 1 | Immediate |
| 2 | 1 minute |
| 3 | 5 minutes |
| 4 | 30 minutes |
| 5 | 2 hours |
Managing Webhooks
/webhooksList all webhooks
/webhooksCreate a new webhook
/webhooks/{id}Update a webhook
/webhooks/{id}Delete a webhook
/webhooks/{id}/testSend a test event
/webhooks/{id}/deliveriesGet delivery history
Create Webhook
{
"name": "ERP Sync",
"url": "https://your-system.com/webhooks/kobo",
"events": ["style.created", "style.updated", "inventory.updated"],
"is_active": true
}Best Practices
Incremental Sync
For efficient data synchronization, use the updated_since filter:
# Store the last sync timestamp
LAST_SYNC="2024-01-15T00:00:00Z"
# Fetch only changed records
curl "https://api.koboplm.com/api/v1/styles?updated_since=$LAST_SYNC" \
-H "X-API-Key: your_api_key"Pagination
Always paginate through results to avoid timeouts:
async function getAllStyles(apiKey) {
let allStyles = [];
let page = 1;
let hasMore = true;
while (hasMore) {
const response = await fetch(
`https://api.koboplm.com/api/v1/styles?page=${page}&per_page=100`,
{ headers: { 'X-API-Key': apiKey } }
);
const data = await response.json();
allStyles = allStyles.concat(data.data);
hasMore = page < data.meta.last_page;
page++;
}
return allStyles;
}Rate Limit Handling
Implement exponential backoff when rate limited:
async function apiRequest(url, options, retries = 3) {
for (let i = 0; i < retries; i++) {
const response = await fetch(url, options);
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After') || 60;
await sleep(retryAfter * 1000 * Math.pow(2, i));
continue;
}
return response;
}
throw new Error('Rate limit exceeded after retries');
}Idempotency
Use idempotency keys for create operations to prevent duplicates:
curl -X POST "https://api.koboplm.com/api/v1/purchase-orders" \
-H "X-API-Key: your_api_key" \
-H "Idempotency-Key: unique-request-id-12345" \
-H "Content-Type: application/json" \
-d '{"supplier_id": 1, ...}'SDK & Tools
Official Libraries
- Coming Soon: JavaScript/TypeScript SDK
- Coming Soon: Python SDK
- Coming Soon: PHP SDK
OpenAPI Specification
Download our OpenAPI 3.0 specification for use with code generators:
Postman Collection
Import our Postman collection to quickly test the API:
Support
- Email: api-support@koboplm.com
- Documentation: https://docs.koboplm.com
- Status Page: https://status.koboplm.com
Last updated: December 2024