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

https://api.koboplm.com/api/v1

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.

bash
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

  1. Log in to Kobo PLM
  2. Go to Account Settings → API Keys
  3. Click Create API Key
  4. Select the scopes (permissions) you need
  5. Copy and securely store your key - it won't be shown again

API Key Scopes

ScopeDescription
*Full access to all resources
styles:readRead styles/products
styles:writeCreate, update, delete styles
components:readRead components/materials
components:writeCreate, update, delete components
suppliers:readRead suppliers
suppliers:writeCreate, update, delete suppliers
purchase_orders:readRead purchase orders
purchase_orders:writeCreate, update, delete purchase orders
inventory:readRead inventory levels
inventory:writeUpdate inventory
customers:readRead customers
customers:writeCreate, update, delete customers
sales_orders:readRead sales orders
sales_orders:writeCreate, update, delete sales orders
deliveries:readRead deliveries
webhooks:readRead webhook configurations
webhooks:writeManage webhooks

Rate Limiting

API requests are rate limited based on your subscription tier:

TierRequests per Minute
Basic100
Professional500
Enterprise2,000

Rate limit headers are included in every response:

http
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1699574400
Rate Limit Exceeded
When rate limited, you'll receive a 429 Too Many Requests response. Implement exponential backoff to handle this gracefully.

Pagination

List endpoints return paginated results. Use these query parameters:

ParameterTypeDescription
pageintegerPage number (default: 1)
per_pageintegerItems per page (default: 25, max: 100)

Response includes pagination metadata:

json
{
  "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:

ParameterTypeDescription
updated_sincedatetimeISO 8601 datetime (e.g., 2024-01-01T00:00:00Z)
created_sincedatetimeISO 8601 datetime (e.g., 2024-01-01T00:00:00Z)
bash
# 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:

CodeDescription
200Success
201Created
204No Content (successful delete)
400Bad Request - Invalid parameters
401Unauthorized - Invalid or missing API key
403Forbidden - Insufficient permissions
404Not Found
422Validation Error
429Rate Limited
500Server Error

Error responses include details:

json
{
  "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.

GET/styles

List all styles with optional filtering and pagination

GET/styles/{id}

Get a specific style by ID

POST/styles

Create a new style

PUT/styles/{id}

Update an existing style

DELETE/styles/{id}

Delete a style

List Styles

ParameterTypeDescription
pageintegerPage number
per_pageintegerItems per page (max 100)
updated_sincedatetimeFilter by update time
created_sincedatetimeFilter by creation time
statusstringFilter by status
season_idintegerFilter by season

Example Request

bash
curl "https://api.koboplm.com/api/v1/styles?per_page=50&status=active" \
  -H "X-API-Key: your_api_key"

Example Response

json
{
  "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

bash
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.

GET/components

List all components

GET/components/{id}

Get a specific component

POST/components

Create a new component

PUT/components/{id}

Update an existing component

DELETE/components/{id}

Delete a component

List Components

ParameterTypeDescription
pageintegerPage number
per_pageintegerItems per page
updated_sincedatetimeFilter by update time
typestringFilter by component type
supplier_idintegerFilter by supplier

Example Response

json
{
  "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

GET/suppliers

List all suppliers

GET/suppliers/{id}

Get a specific supplier

POST/suppliers

Create a new supplier

PUT/suppliers/{id}

Update an existing supplier

DELETE/suppliers/{id}

Delete a supplier

List Suppliers

ParameterTypeDescription
pageintegerPage number
per_pageintegerItems per page
updated_sincedatetimeFilter by update time
countrystringFilter by country code
typestringFilter by supplier type

Example Response

json
{
  "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

GET/purchase-orders

List all purchase orders

GET/purchase-orders/{id}

Get a specific purchase order

POST/purchase-orders

Create a new purchase order

PUT/purchase-orders/{id}

Update an existing purchase order

DELETE/purchase-orders/{id}

Delete a draft purchase order

Status Values

draft, pending,confirmed, in_production,shipped, delivered,cancelled

Example Response

json
{
  "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

GET/inventory

List inventory items

GET/inventory/{id}

Get a specific inventory item

PUT/inventory/{id}

Update inventory levels

POST/inventory/bulk-update

Bulk update inventory

List Inventory

ParameterTypeDescription
pageintegerPage number
per_pageintegerItems per page
updated_sincedatetimeFilter by update time
style_idintegerFilter by style
location_idintegerFilter by location
low_stockbooleanFilter low stock items

Bulk Update Example

json
{
  "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

GET/customers

List all customers

GET/customers/{id}

Get a specific customer

POST/customers

Create a new customer

PUT/customers/{id}

Update an existing customer

DELETE/customers/{id}

Delete a customer

List Customers

ParameterTypeDescription
pageintegerPage number
per_pageintegerItems per page
updated_sincedatetimeFilter by update time
typestringFilter by type (wholesale, retail)

Sales Orders

GET/sales-orders

List all sales orders

GET/sales-orders/{id}

Get a specific sales order

POST/sales-orders

Create a new sales order

PUT/sales-orders/{id}

Update an existing sales order

DELETE/sales-orders/{id}

Delete a sales order

Status Values

draft, pending,confirmed, processing,shipped, delivered,cancelled

Deliveries

Deliveries are read-only via the API.

GET/deliveries

List all deliveries

GET/deliveries/{id}

Get a specific delivery

List Deliveries

ParameterTypeDescription
pageintegerPage number
per_pageintegerItems per page
updated_sincedatetimeFilter by update time
statusstringFilter by status
purchase_order_idintegerFilter 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

EventDescription
style.createdA new style was created
style.updatedA style was updated
style.deletedA style was deleted
style.status_changedA style's status changed

Component Events

EventDescription
component.createdA new component was created
component.updatedA component was updated
component.deletedA component was deleted

Supplier Events

EventDescription
supplier.createdA new supplier was created
supplier.updatedA supplier was updated
supplier.deletedA supplier was deleted

Purchase Order Events

EventDescription
purchase_order.createdA new PO was created
purchase_order.updatedA PO was updated
purchase_order.status_changedA PO's status changed
purchase_order.confirmedA PO was confirmed
purchase_order.cancelledA PO was cancelled

Inventory Events

EventDescription
inventory.updatedInventory levels changed
inventory.low_stockInventory fell below reorder point

Customer Events

EventDescription
customer.createdA new customer was created
customer.updatedA customer was updated
customer.deletedA customer was deleted

Sales Order Events

EventDescription
sales_order.createdA new sales order was created
sales_order.updatedA sales order was updated
sales_order.status_changedA sales order's status changed

Delivery Events

EventDescription
delivery.createdA new delivery was created
delivery.checked_inA delivery was received
delivery.status_changedA delivery's status changed

Webhook Payload

All webhooks send a JSON payload with the following structure:

json
{
  "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

HeaderDescription
Content-Typeapplication/json
User-AgentKOBO-PLM-Webhooks/1.0
X-Webhook-EventEvent type (e.g., style.updated)
X-Webhook-Event-IdUnique event ID (UUID)
X-Webhook-TimestampUnix timestamp
X-Webhook-SignatureHMAC-SHA256 signature

Signature Verification

To verify that a webhook came from Kobo PLM, validate the signature:

javascript
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');
});
python
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}"
    )
php
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:

AttemptDelay
1Immediate
21 minute
35 minutes
430 minutes
52 hours

Managing Webhooks

GET/webhooks

List all webhooks

POST/webhooks

Create a new webhook

PUT/webhooks/{id}

Update a webhook

DELETE/webhooks/{id}

Delete a webhook

POST/webhooks/{id}/test

Send a test event

GET/webhooks/{id}/deliveries

Get delivery history

Create Webhook

json
{
  "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:

bash
# 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:

javascript
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:

javascript
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:

bash
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:

https://api.koboplm.com/api/v1/openapi.yaml

Postman Collection

Import our Postman collection to quickly test the API:

https://api.koboplm.com/api/v1/postman-collection.json

Support

  • Email: api-support@koboplm.com
  • Documentation: https://docs.koboplm.com
  • Status Page: https://status.koboplm.com

Last updated: December 2024