📖 Sellstory Open API v1

Complete API Documentation - Customer & Product Integration Guide

🔐 Authentication

1. Request API Credentials

āļ‚āļ­ API Key āđāļĨāļ° API Secret āļŠāļģāļŦāļĢāļąāļš workspace āļ‚āļ­āļ‡āļ„āļļāļ“

POST /api/v1/auth/request-credentials

Request Body:

Field Type Required Description
workspaceId string ✅ āļšāļąāļ‡āļ„āļąāļš āļĢāļŦāļąāļŠ Workspace āļ‚āļ­āļ‡āļ„āļļāļ“
requestedBy string ✅ āļšāļąāļ‡āļ„āļąāļš Email āļ‚āļ­āļ‡āļœāļđāđ‰āļ‚āļ­ API Key
purpose string ✅ āļšāļąāļ‡āļ„āļąāļš āļ§āļąāļ•āļ–āļļāļ›āļĢāļ°āļŠāļ‡āļ„āđŒāđƒāļ™āļāļēāļĢāđƒāļŠāđ‰āļ‡āļēāļ™ API
environment string ⚩ āđ„āļĄāđˆāļšāļąāļ‡āļ„āļąāļš production āļŦāļĢāļ·āļ­ sandbox

Example Request:

{
  "workspaceId": "your-workspace-id",
  "requestedBy": "your-email@company.com",
  "purpose": "Integration with CRM System",
  "environment": "production"
}

Example Response: 201 Created

{
  "success": true,
  "data": {
    "apiKey": "sk_live_xxxxxxxxxxxxxxxx",
    "apiSecret": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "environment": "production",
    "scopes": ["customer:read", "customer:write", "product:read", "product:write"],
    "rateLimit": 100,
    "createdAt": "2025-11-06T07:00:00.000Z"
  },
  "requestId": "req_xxxxxxxxxxxxx"
}
⚠ïļ
āļŠāļģāļ„āļąāļ! apiSecret āļˆāļ°āđāļŠāļ”āļ‡āđ€āļžāļĩāļĒāļ‡āļ„āļĢāļąāđ‰āļ‡āđ€āļ”āļĩāļĒāļ§ āļāļĢāļļāļ“āļēāđ€āļāđ‡āļšāđ„āļ§āđ‰āļ­āļĒāđˆāļēāļ‡āļ›āļĨāļ­āļ”āļ āļąāļĒ!

2. Generate JWT Token

āļŠāļĢāđ‰āļēāļ‡ JWT Token āļŠāļģāļŦāļĢāļąāļšāđƒāļŠāđ‰āđ€āļĢāļĩāļĒāļ API āļ­āļ·āđˆāļ™āđ†

POST /api/v1/auth/token

Request Body:

Field Type Required Description
apiKey string ✅ āļšāļąāļ‡āļ„āļąāļš API Key āļ—āļĩāđˆāđ„āļ”āđ‰āļˆāļēāļāļ‚āļąāđ‰āļ™āļ•āļ­āļ™āļ—āļĩāđˆ 1
apiSecret string ✅ āļšāļąāļ‡āļ„āļąāļš API Secret āļ—āļĩāđˆāđ„āļ”āđ‰āļˆāļēāļāļ‚āļąāđ‰āļ™āļ•āļ­āļ™āļ—āļĩāđˆ 1

Example Response: 200 OK

{
  "success": true,
  "data": {
    "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "tokenType": "Bearer",
    "expiresIn": 3600,
    "scope": "customer:read customer:write product:read product:write"
  },
  "requestId": "req_xxxxxxxxxxxxx"
}
â„đïļ
Token Expiration: JWT Token āļŦāļĄāļ”āļ­āļēāļĒāļļāđƒāļ™ 1 āļŠāļąāđˆāļ§āđ‚āļĄāļ‡ (3600 āļ§āļīāļ™āļēāļ—āļĩ)

ðŸ‘Ĩ Customer APIs

3. Create/Update Customer (Upsert)

āļŠāļĢāđ‰āļēāļ‡āļŦāļĢāļ·āļ­āļ­āļąāļ›āđ€āļ”āļ•āļ‚āđ‰āļ­āļĄāļđāļĨāļĨāļđāļāļ„āđ‰āļē (āļĢāļ°āļšāļšāļˆāļ°āļ„āđ‰āļ™āļŦāļēāļ”āđ‰āļ§āļĒ customId āļŦāļĢāļ·āļ­ email āļ–āđ‰āļēāļĄāļĩāļ­āļĒāļđāđˆāđāļĨāđ‰āļ§āļˆāļ°āļ­āļąāļ›āđ€āļ”āļ• āļ–āđ‰āļēāđ„āļĄāđˆāļĄāļĩāļˆāļ°āļŠāļĢāđ‰āļēāļ‡āđƒāļŦāļĄāđˆ)

POST /api/v1/customers/upsert
âœĻ
Auto Company Creation: āļ–āđ‰āļēāļŠāđˆāļ‡ company object āļĄāļēāļ”āđ‰āļ§āļĒ āļĢāļ°āļšāļšāļˆāļ°:
  • āļŠāļĢāđ‰āļēāļ‡/āļ­āļąāļ›āđ€āļ”āļ• Company āļ­āļąāļ•āđ‚āļ™āļĄāļąāļ•āļī
  • Link Customer āļāļąāļš Company

Headers:

Authorization: Bearer {accessToken}
Content-Type: application/json

Required Fields (āļŸāļīāļĨāļ”āđŒāļšāļąāļ‡āļ„āļąāļš):

Field Type Description
name string āļŠāļ·āđˆāļ­-āļ™āļēāļĄāļŠāļāļļāļĨ āļĨāļđāļāļ„āđ‰āļē

Optional Fields (āļŸāļīāļĨāļ”āđŒāđ„āļĄāđˆāļšāļąāļ‡āļ„āļąāļš):

Field Type Description Example
customId string āļĢāļŦāļąāļŠāļĨāļđāļāļ„āđ‰āļēāļˆāļēāļāļĢāļ°āļšāļšāļ‚āļ­āļ‡āļ„āļļāļ“ "CUST-001"
email string āļ­āļĩāđ€āļĄāļĨ "john@example.com"
phone string āđ€āļšāļ­āļĢāđŒāđ‚āļ—āļĢāļĻāļąāļžāļ—āđŒ "0812345678"
customerType string āļ›āļĢāļ°āđ€āļ āļ—: Customer, Lead, Prospect "Customer"
gender string āđ€āļžāļĻ: Male, Female, Other "Male"
source string āđāļŦāļĨāđˆāļ‡āļ—āļĩāđˆāļĄāļē "Facebook Ads"
tags string[] āđāļ—āđ‡āļ ["vip", "wholesale"]
address object āļ—āļĩāđˆāļ­āļĒāļđāđˆāļĨāļđāļāļ„āđ‰āļē (object format) { addressLine1, subdistrict, district, province, postalCode }
addressLine1 string āļ—āļĩāđˆāļ­āļĒāļđāđˆ (flat format - legacy) "123 āļ–āļ™āļ™āļŠāļļāļ‚āļļāļĄāļ§āļīāļ—"
company object âœĻ Auto-create Company! āļ–āđ‰āļēāļŠāđˆāļ‡āļĄāļē āļˆāļ°āļŠāļĢāđ‰āļēāļ‡āļšāļĢāļīāļĐāļąāļ—āđāļĨāļ° link āļāļąāļ™ āļ”āļđāļ•āļąāļ§āļ­āļĒāđˆāļēāļ‡āļ”āđ‰āļēāļ™āļĨāđˆāļēāļ‡
customFields object āļŸāļīāļĨāļ”āđŒāđ€āļžāļīāđˆāļĄāđ€āļ•āļīāļĄ {"āļŦāļĄāļēāļĒāđ€āļŦāļ•āļļ": "VIP"}

Company Object Fields (āļŠāļģāļŦāļĢāļąāļš auto-create company):

Field Type Description Fallback
customId string āļĢāļŦāļąāļŠāļšāļĢāļīāļĐāļąāļ—āļˆāļēāļāļĢāļ°āļšāļšāļ‚āļ­āļ‡āļ„āļļāļ“ (āđƒāļŠāđ‰āļ„āđ‰āļ™āļŦāļē company āļ—āļĩāđˆāļĄāļĩāļ­āļĒāļđāđˆ) -
name string ✅ āļšāļąāļ‡āļ„āļąāļš āļŠāļ·āđˆāļ­āļšāļĢāļīāļĐāļąāļ— -
taxId string āđ€āļĨāļ‚āļ›āļĢāļ°āļˆāļģāļ•āļąāļ§āļœāļđāđ‰āđ€āļŠāļĩāļĒāļ āļēāļĐāļĩ (āđƒāļŠāđ‰āļ„āđ‰āļ™āļŦāļē company āļ—āļĩāđˆāļĄāļĩāļ­āļĒāļđāđˆ) -
branch string āļŠāļēāļ‚āļē "āļŠāļģāļ™āļąāļāļ‡āļēāļ™āđƒāļŦāļāđˆ"
phone string āđ€āļšāļ­āļĢāđŒāļšāļĢāļīāļĐāļąāļ— āđƒāļŠāđ‰ phone āļ‚āļ­āļ‡ customer
email string āļ­āļĩāđ€āļĄāļĨāļšāļĢāļīāļĐāļąāļ— āđƒāļŠāđ‰ email āļ‚āļ­āļ‡ customer
website string āđ€āļ§āđ‡āļšāđ„āļ‹āļ•āđŒ āđƒāļŠāđ‰ website āļ‚āļ­āļ‡ customer
address string āļ—āļĩāđˆāļ­āļĒāļđāđˆāļšāļĢāļīāļĐāļąāļ— āđƒāļŠāđ‰ address āļ‚āļ­āļ‡ customer
addressLine1 string āļšāđ‰āļēāļ™āđ€āļĨāļ‚āļ—āļĩāđˆ/āļ­āļēāļ„āļēāļĢ āđƒāļŠāđ‰āļˆāļēāļ customer
subdistrict string āļ•āļģāļšāļĨ/āđāļ‚āļ§āļ‡ āđƒāļŠāđ‰āļˆāļēāļ customer
district string āļ­āļģāđ€āļ āļ­/āđ€āļ‚āļ• āđƒāļŠāđ‰āļˆāļēāļ customer
province string āļˆāļąāļ‡āļŦāļ§āļąāļ” āđƒāļŠāđ‰āļˆāļēāļ customer
postalCode string āļĢāļŦāļąāļŠāđ„āļ›āļĢāļĐāļ“āļĩāļĒāđŒ āđƒāļŠāđ‰āļˆāļēāļ customer

Example Request (Customer Only):

{
  "customId": "CUST-001",
  "name": "āļŠāļĄāļŠāļēāļĒ āđƒāļˆāļ”āļĩ",
  "email": "somchai@example.com",
  "phone": "0812345678",
  "customerType": "Customer",
  "gender": "Male",
  "source": "Facebook",
  "tags": ["vip", "wholesale"],
  "address": {
    "addressLine1": "123 āļ–āļ™āļ™āļŠāļļāļ‚āļļāļĄāļ§āļīāļ—",
    "subdistrict": "āļ„āļĨāļ­āļ‡āđ€āļ•āļĒ",
    "district": "āļ„āļĨāļ­āļ‡āđ€āļ•āļĒ",
    "province": "āļāļĢāļļāļ‡āđ€āļ—āļžāļĄāļŦāļēāļ™āļ„āļĢ",
    "postalCode": "10110"
  },
  "customFields": {
    "āļ›āļĢāļ°āđ€āļ āļ—āļ˜āļļāļĢāļāļīāļˆ": "āļ„āđ‰āļēāļŠāđˆāļ‡",
    "āļ§āļ‡āđ€āļ‡āļīāļ™āđ€āļ„āļĢāļ”āļīāļ•": "100000"
  }
}

Example Request (Customer + Company):

ðŸ’Ą
Auto Company Features:
  • āļ–āđ‰āļē Company āļĄāļĩ customId, taxId āļŦāļĢāļ·āļ­ name āļ•āļĢāļ‡āļāļąāļšāļ—āļĩāđˆāļĄāļĩāļ­āļĒāļđāđˆ → āļ­āļąāļ›āđ€āļ”āļ•
  • āļ–āđ‰āļēāđ„āļĄāđˆāļĄāļĩ → āļŠāļĢāđ‰āļēāļ‡ Company āđƒāļŦāļĄāđˆ
  • āļŸāļīāļĨāļ”āđŒāļ—āļĩāđˆāđ„āļĄāđˆāđ„āļ”āđ‰āļŠāđˆāļ‡āđƒāļ™ company → āđƒāļŠāđ‰āļ‚āđ‰āļ­āļĄāļđāļĨāļˆāļēāļ customer āđāļ—āļ™
  • Response āļˆāļ°āļĄāļĩāļ—āļąāđ‰āļ‡ data (customer) āđāļĨāļ° company
{
  "customId": "CUST-001",
  "name": "āļŠāļĄāļŠāļēāļĒ āđƒāļˆāļ”āļĩ",
  "email": "somchai@example.com",
  "phone": "0812345678",
  "customerType": "Customer",
  "gender": "Male",
  "source": "Facebook",
  "tags": ["vip", "wholesale"],
  "address": {
    "addressLine1": "123 āļ–āļ™āļ™āļŠāļļāļ‚āļļāļĄāļ§āļīāļ—",
    "subdistrict": "āļ„āļĨāļ­āļ‡āđ€āļ•āļĒ",
    "district": "āļ„āļĨāļ­āļ‡āđ€āļ•āļĒ",
    "province": "āļāļĢāļļāļ‡āđ€āļ—āļžāļĄāļŦāļēāļ™āļ„āļĢ",
    "postalCode": "10110"
  },
  "company": {
    "customId": "COMP-001",
    "name": "āļšāļĢāļīāļĐāļąāļ— āļ‹āļ·āđ‰āļ­āļĄāļēāļ āļˆāļģāļāļąāļ”",
    "taxId": "0123456789012",
    "branch": "āļŠāļģāļ™āļąāļāļ‡āļēāļ™āđƒāļŦāļāđˆ"
  },
  "customFields": {
    "āļ›āļĢāļ°āđ€āļ āļ—āļ˜āļļāļĢāļāļīāļˆ": "āļ„āđ‰āļēāļŠāđˆāļ‡",
    "āļ§āļ‡āđ€āļ‡āļīāļ™āđ€āļ„āļĢāļ”āļīāļ•": "100000"
  }
}

Note: āđƒāļ™āļ•āļąāļ§āļ­āļĒāđˆāļēāļ‡āļ™āļĩāđ‰ company āđ„āļĄāđˆāđ„āļ”āđ‰āļŠāđˆāļ‡ phone, email, address āļĄāļē āļĢāļ°āļšāļšāļˆāļ°āđƒāļŠāđ‰āļ‚āđ‰āļ­āļĄāļđāļĨāļˆāļēāļ customer (somchai@example.com, 0812345678, āļ—āļĩāđˆāļ­āļĒāļđāđˆāļ„āļĨāļ­āļ‡āđ€āļ•āļĒ) āđāļ—āļ™āļ­āļąāļ•āđ‚āļ™āļĄāļąāļ•āļī

Response: 201 Created

{
  "success": true,
  "data": {
    "action": "created",
    "data": {
      "id": "abc123xyz",
      "customId": "CUST-001",
      "name": "āļŠāļĄāļŠāļēāļĒ āđƒāļˆāļ”āļĩ",
      "email": "somchai@example.com",
      "customerType": "Customer",
      "companyNames": [{
        "id": "company456",
        "label": "āļŠāļģāļ™āļąāļāļ‡āļēāļ™āđƒāļŦāļāđˆ",
        "value": "āļšāļĢāļīāļĐāļąāļ— āļ‹āļ·āđ‰āļ­āļĄāļēāļ āļˆāļģāļāļąāļ”"
      }],
      "workspaceId": "your-workspace-id",
      "createdAt": 1699257600000,
      "updatedAt": 1699257600000
    },
    "company": {
      "id": "company456",
      "name": "āļšāļĢāļīāļĐāļąāļ— āļ‹āļ·āđ‰āļ­āļĄāļēāļ āļˆāļģāļāļąāļ”",
      "taxId": "0123456789012",
      "branch": "āļŠāļģāļ™āļąāļāļ‡āļēāļ™āđƒāļŦāļāđˆ",
      "emails": [{"value": "somchai@example.com"}],
      "phones": [{"value": "0812345678"}],
      "associatedCustomerIds": ["abc123xyz"],
      "createdAt": 1699257600000
    }
  },
  "requestId": "req_xxxxxxxxxxxxx"
}

Response: 200 OK (Updated)

{
  "success": true,
  "data": {
    "action": "updated",
    "customer": {
      "id": "abc123xyz",
      "customId": "CUST-001",
      "name": "āļŠāļĄāļŠāļēāļĒ āđƒāļˆāļ”āļĩ (āđāļāđ‰āđ„āļ‚)",
      "email": "somchai@example.com",
      "updatedAt": 1699257700000
    }
  },
  "requestId": "req_xxxxxxxxxxxxx"
}

4. Get Customer by ID

GET /api/v1/customers/{id}

5. Get Customer by Custom ID

GET /api/v1/customers/customId/{customId}

6. List Customers

GET /api/v1/customers?page=1&limit=10

Query Parameters (āļ—āļąāđ‰āļ‡āļŦāļĄāļ”āđ„āļĄāđˆāļšāļąāļ‡āļ„āļąāļš):

Parameter Type Description Default
page number āļŦāļ™āđ‰āļēāļ—āļĩāđˆāļ•āđ‰āļ­āļ‡āļāļēāļĢ 1
limit number āļˆāļģāļ™āļ§āļ™āļĢāļēāļĒāļāļēāļĢāļ•āđˆāļ­āļŦāļ™āđ‰āļē (āļŠāļđāļ‡āļŠāļļāļ” 100) 20
search string āļ„āļģāļ„āđ‰āļ™āļŦāļē (āļŠāļ·āđˆāļ­, āļ­āļĩāđ€āļĄāļĨ, āđ€āļšāļ­āļĢāđŒāđ‚āļ—āļĢ) -
customerType string āļāļĢāļ­āļ‡āļ•āļēāļĄāļ›āļĢāļ°āđ€āļ āļ— -
sortBy string āđ€āļĢāļĩāļĒāļ‡āļĨāļģāļ”āļąāļšāļ•āļēāļĄāļŸāļīāļĨāļ”āđŒ updatedAt
sortOrder string asc āļŦāļĢāļ·āļ­ desc desc

Response Headers (Rate Limiting):

Header Description Example
X-RateLimit-Limit āļˆāļģāļ™āļ§āļ™ requests āļŠāļđāļ‡āļŠāļļāļ”āļ•āđˆāļ­āļ™āļēāļ—āļĩ 100
X-RateLimit-Remaining āļˆāļģāļ™āļ§āļ™ requests āļ—āļĩāđˆāđ€āļŦāļĨāļ·āļ­ 95
X-RateLimit-Reset āđ€āļ§āļĨāļēāļ—āļĩāđˆāļĢāļĩāđ€āļ‹āđ‡āļ• (Unix timestamp) 1699257660

ðŸ“Ķ Product APIs

7. Create/Update Product (Upsert)

āļŠāļĢāđ‰āļēāļ‡āļŦāļĢāļ·āļ­āļ­āļąāļ›āđ€āļ”āļ•āļ‚āđ‰āļ­āļĄāļđāļĨāļŠāļīāļ™āļ„āđ‰āļē (āļĢāļ°āļšāļšāļˆāļ°āļ„āđ‰āļ™āļŦāļēāļ”āđ‰āļ§āļĒ customId, sku āļŦāļĢāļ·āļ­ barcode āļ–āđ‰āļēāļĄāļĩāļ­āļĒāļđāđˆāđāļĨāđ‰āļ§āļˆāļ°āļ­āļąāļ›āđ€āļ”āļ• āļ–āđ‰āļēāđ„āļĄāđˆāļĄāļĩāļˆāļ°āļŠāļĢāđ‰āļēāļ‡āđƒāļŦāļĄāđˆ)

POST /api/v1/products/upsert
â„đïļ
Upsert Priority: āļĢāļ°āļšāļšāļˆāļ°āļ„āđ‰āļ™āļŦāļēāļ•āļēāļĄāļĨāļģāļ”āļąāļš 1) customId 2) sku 3) barcode

Headers:

Authorization: Bearer {accessToken}
Content-Type: application/json

Required Fields (āļŸāļīāļĨāļ”āđŒāļšāļąāļ‡āļ„āļąāļš):

Field Type Description
name string āļŠāļ·āđˆāļ­āļŠāļīāļ™āļ„āđ‰āļē
price number āļĢāļēāļ„āļēāļ‚āļēāļĒ (āļ•āđ‰āļ­āļ‡ >= 0)

Optional Fields (āļŸāļīāļĨāļ”āđŒāđ„āļĄāđˆāļšāļąāļ‡āļ„āļąāļš):

Field Type Description Example
customId string āļĢāļŦāļąāļŠāļŠāļīāļ™āļ„āđ‰āļēāļˆāļēāļāļĢāļ°āļšāļšāļ‚āļ­āļ‡āļ„āļļāļ“ (āđƒāļŠāđ‰āļŠāļģāļŦāļĢāļąāļš upsert) "PROD-001"
sku string āļĢāļŦāļąāļŠāļŠāļīāļ™āļ„āđ‰āļē (Stock Keeping Unit) "SKU-001"
barcode string āļšāļēāļĢāđŒāđ‚āļ„āđ‰āļ” "8850999320014"
description string āļĢāļēāļĒāļĨāļ°āđ€āļ­āļĩāļĒāļ”āļŠāļīāļ™āļ„āđ‰āļē "āļŠāļīāļ™āļ„āđ‰āļēāļ„āļļāļ“āļ āļēāļžāļ”āļĩ"
category string āļŦāļĄāļ§āļ”āļŦāļĄāļđāđˆāļŠāļīāļ™āļ„āđ‰āļē "āļ­āļīāđ€āļĨāđ‡āļāļ—āļĢāļ­āļ™āļīāļāļŠāđŒ"
costPrice number āļĢāļēāļ„āļēāļ—āļļāļ™ 150
unit string āļŦāļ™āđˆāļ§āļĒāļ™āļąāļš "āļŠāļīāđ‰āļ™", "āļāļĨāđˆāļ­āļ‡"
initialStock number āļŠāļ•āđ‡āļ­āļāđ€āļĢāļīāđˆāļĄāļ•āđ‰āļ™ (āļŠāļģāļŦāļĢāļąāļšāļŠāļīāļ™āļ„āđ‰āļēāđƒāļŦāļĄāđˆ) 100
availableStock number āļŠāļ•āđ‡āļ­āļāļ—āļĩāđˆāļĄāļĩ (āļŠāļģāļŦāļĢāļąāļšāļ­āļąāļ›āđ€āļ”āļ•) 50
reorderLevel number āļˆāļļāļ”āļŠāļąāđˆāļ‡āļ‹āļ·āđ‰āļ­āđƒāļŦāļĄāđˆ 10
targetStockLevel number āļŠāļ•āđ‡āļ­āļāđ€āļ›āđ‰āļēāļŦāļĄāļēāļĒ 100
supplier string āļœāļđāđ‰āļˆāļąāļ”āļˆāļģāļŦāļ™āđˆāļēāļĒ "ABC Supply Co."
status string āļŠāļ–āļēāļ™āļ°: active, draft, discontinued "active"
imageUrl string URL āļĢāļđāļ›āļ āļēāļžāļŦāļĨāļąāļ "https://..."
imageSet string[] āļĢāļđāļ›āļ āļēāļžāđ€āļžāļīāđˆāļĄāđ€āļ•āļīāļĄ ["https://...", "https://..."]
showInCatalog boolean āđāļŠāļ”āļ‡āđƒāļ™āđāļ„āđ‡āļ•āļ•āļēāļĨāđ‡āļ­āļ true
hashtags string[] āđāļŪāļŠāđāļ—āđ‡āļ ["āļ‚āļēāļĒāļ”āļĩ", "āđ‚āļ›āļĢāđ‚āļĄāļŠāļąāđˆāļ™"]
customFields object āļŸāļīāļĨāļ”āđŒāđ€āļžāļīāđˆāļĄāđ€āļ•āļīāļĄ {"āļ§āļąāļ™āļŦāļĄāļ”āļ­āļēāļĒāļļ": "2025-12-31"}
â„đïļ
Stock Management: āļŠāļģāļŦāļĢāļąāļšāļŠāļīāļ™āļ„āđ‰āļēāđƒāļŦāļĄāđˆ āļĢāļ°āļšāļšāļˆāļ°āđƒāļŠāđ‰ initialStock āđ€āļ›āđ‡āļ™āļ„āđˆāļēāđ€āļĢāļīāđˆāļĄāļ•āđ‰āļ™āļ—āļąāđ‰āļ‡ initialStock āđāļĨāļ° availableStock āļŦāļēāļāđ„āļĄāđˆāļĢāļ°āļšāļļāļˆāļ°āđ€āļ›āđ‡āļ™ 0

Example Request:

{
  "sku": "SKU-001",
  "barcode": "8850999320014",
  "name": "āđ€āļŠāļ·āđ‰āļ­āļĒāļ·āļ”āļ„āļ­āļāļĨāļĄ āļŠāļĩāļ‚āļēāļ§",
  "description": "āđ€āļŠāļ·āđ‰āļ­āļĒāļ·āļ”āļœāđ‰āļēāļ„āļ­āļ•āļ•āļ­āļ™ 100% āļŠāļĩāļ‚āļēāļ§ āđƒāļŠāđˆāļŠāļšāļēāļĒ",
  "price": 299,
  "costPrice": 150,
  "category": "āđ€āļŠāļ·āđ‰āļ­āļœāđ‰āļē",
  "unit": "āļ•āļąāļ§",
  "initialStock": 100,
  "reorderLevel": 10,
  "targetStockLevel": 100,
  "supplier": "ABC Textile Co.",
  "status": "active",
  "imageUrl": "https://example.com/shirt-white.jpg",
  "imageSet": [
    "https://example.com/shirt-white-front.jpg",
    "https://example.com/shirt-white-back.jpg"
  ],
  "showInCatalog": true,
  "hashtags": ["āđ€āļŠāļ·āđ‰āļ­āļœāđ‰āļē", "āļ‚āļēāļĒāļ”āļĩ", "basic"],
  "customFields": {
    "āđāļšāļĢāļ™āļ”āđŒ": "MyBrand",
    "āļ›āļĢāļ°āđ€āļ—āļĻāļœāļĨāļīāļ•": "āđ„āļ—āļĒ"
  }
}

Response: 201 Created

{
  "success": true,
  "data": {
    "action": "created",
    "product": {
      "id": "prod123xyz",
      "sku": "SKU-001",
      "sku_lower": "sku-001",
      "barcode": "8850999320014",
      "name": "āđ€āļŠāļ·āđ‰āļ­āļĒāļ·āļ”āļ„āļ­āļāļĨāļĄ āļŠāļĩāļ‚āļēāļ§",
      "price": 299,
      "initialStock": 100,
      "availableStock": 100,
      "workspaceId": "your-workspace-id",
      "createdAt": 1699257600000,
      "updatedAt": 1699257600000
    }
  },
  "requestId": "req_xxxxxxxxxxxxx"
}

Response: 200 OK (Updated)

{
  "success": true,
  "data": {
    "action": "updated",
    "product": {
      "id": "prod123xyz",
      "sku": "SKU-001",
      "name": "āđ€āļŠāļ·āđ‰āļ­āļĒāļ·āļ”āļ„āļ­āļāļĨāļĄ āļŠāļĩāļ‚āļēāļ§ (āļ­āļąāļ›āđ€āļ”āļ•)",
      "price": 349,
      "availableStock": 75,
      "updatedAt": 1699257700000
    }
  },
  "requestId": "req_xxxxxxxxxxxxx"
}

8. Get Product by ID

GET /api/v1/products/{id}

āļ”āļķāļ‡āļ‚āđ‰āļ­āļĄāļđāļĨāļŠāļīāļ™āļ„āđ‰āļēāļ”āđ‰āļ§āļĒ Firestore Document ID

9. Get Product by Custom ID

GET /api/v1/products/customId/{customId}

āļ”āļķāļ‡āļ‚āđ‰āļ­āļĄāļđāļĨāļŠāļīāļ™āļ„āđ‰āļēāļ”āđ‰āļ§āļĒāļĢāļŦāļąāļŠāļŠāļīāļ™āļ„āđ‰āļēāļˆāļēāļāļĢāļ°āļšāļšāļ‚āļ­āļ‡āļ„āļļāļ“

10. Get Product by SKU

GET /api/v1/products/sku/{sku}

āļ”āļķāļ‡āļ‚āđ‰āļ­āļĄāļđāļĨāļŠāļīāļ™āļ„āđ‰āļēāļ”āđ‰āļ§āļĒāļĢāļŦāļąāļŠ SKU (āđ„āļĄāđˆāļŠāļ™āđƒāļˆāļ•āļąāļ§āļžāļīāļĄāļžāđŒāđ€āļĨāđ‡āļ-āđƒāļŦāļāđˆ)

11. Get Product by Barcode

GET /api/v1/products/barcode/{barcode}

āļ”āļķāļ‡āļ‚āđ‰āļ­āļĄāļđāļĨāļŠāļīāļ™āļ„āđ‰āļēāļ”āđ‰āļ§āļĒāļšāļēāļĢāđŒāđ‚āļ„āđ‰āļ”

12. List Products

GET /api/v1/products?page=1&limit=20

Query Parameters (āļ—āļąāđ‰āļ‡āļŦāļĄāļ”āđ„āļĄāđˆāļšāļąāļ‡āļ„āļąāļš):

Parameter Type Description Default
page number āļŦāļ™āđ‰āļēāļ—āļĩāđˆāļ•āđ‰āļ­āļ‡āļāļēāļĢ 1
limit number āļˆāļģāļ™āļ§āļ™āļĢāļēāļĒāļāļēāļĢāļ•āđˆāļ­āļŦāļ™āđ‰āļē (āļŠāļđāļ‡āļŠāļļāļ” 100) 20
search string āļ„āļģāļ„āđ‰āļ™āļŦāļē (āļŠāļ·āđˆāļ­, āļĢāļēāļĒāļĨāļ°āđ€āļ­āļĩāļĒāļ”, SKU, āļšāļēāļĢāđŒāđ‚āļ„āđ‰āļ”) -
category string āļāļĢāļ­āļ‡āļ•āļēāļĄāļŦāļĄāļ§āļ”āļŦāļĄāļđāđˆ -
status string active, draft, discontinued -
minPrice number āļĢāļēāļ„āļēāļ•āđˆāļģāļŠāļļāļ” -
maxPrice number āļĢāļēāļ„āļēāļŠāļđāļ‡āļŠāļļāļ” -
inStock boolean āļāļĢāļ­āļ‡āđ€āļ‰āļžāļēāļ°āļŠāļīāļ™āļ„āđ‰āļēāđƒāļ™āļŠāļ•āđ‡āļ­āļ -
hashtags string āđāļŪāļŠāđāļ—āđ‡āļ (āļ„āļąāđˆāļ™āļ”āđ‰āļ§āļĒ comma) -
sortBy string āđ€āļĢāļĩāļĒāļ‡āļĨāļģāļ”āļąāļšāļ•āļēāļĄāļŸāļīāļĨāļ”āđŒ (name, price, updatedAt) updatedAt
sortOrder string asc āļŦāļĢāļ·āļ­ desc desc

Example Request:

GET /api/v1/products?page=1&limit=10&category=āđ€āļŠāļ·āđ‰āļ­āļœāđ‰āļē&inStock=true&sortBy=price&sortOrder=asc
Authorization: Bearer {accessToken}

Example Response: 200 OK

{
  "success": true,
  "data": {
    "products": [
      {
        "id": "prod123xyz",
        "sku": "SKU-001",
        "barcode": "8850999320014",
        "name": "āđ€āļŠāļ·āđ‰āļ­āļĒāļ·āļ”āļ„āļ­āļāļĨāļĄ āļŠāļĩāļ‚āļēāļ§",
        "price": 299,
        "availableStock": 75,
        "category": "āđ€āļŠāļ·āđ‰āļ­āļœāđ‰āļē",
        "status": "active"
      }
    ],
    "pagination": {
      "page": 1,
      "limit": 10,
      "total": 1,
      "totalPages": 1,
      "hasMore": false
    }
  },
  "requestId": "req_xxxxxxxxxxxxx"
}

❌ Error Handling

Error Response Format

{
  "error": "error_code",
  "message": "Human readable error message",
  "details": {
    "additional": "error details"
  },
  "requestId": "req_xxxxxxxxxxxxx",
  "timestamp": "2025-11-06T07:00:00.000Z"
}

Common Error Codes

Error Code HTTP Status Description
validation_error 400 āļ‚āđ‰āļ­āļĄāļđāļĨāļ—āļĩāđˆāļŠāđˆāļ‡āļĄāļēāđ„āļĄāđˆāļ–āļđāļāļ•āđ‰āļ­āļ‡
invalid_credentials 401 API Key āļŦāļĢāļ·āļ­ Secret āđ„āļĄāđˆāļ–āļđāļāļ•āđ‰āļ­āļ‡
invalid_token 401 JWT Token āđ„āļĄāđˆāļ–āļđāļāļ•āđ‰āļ­āļ‡āļŦāļĢāļ·āļ­āļŦāļĄāļ”āļ­āļēāļĒāļļ
forbidden 403 āđ„āļĄāđˆāļĄāļĩāļŠāļīāļ—āļ˜āļīāđŒāđ€āļ‚āđ‰āļēāļ–āļķāļ‡
bot_detected 403 āļ•āļĢāļ§āļˆāļžāļšāļžāļĪāļ•āļīāļāļĢāļĢāļĄāļ—āļĩāđˆāļ™āđˆāļēāļŠāļ‡āļŠāļąāļĒ
not_found 404 āđ„āļĄāđˆāļžāļšāļ‚āđ‰āļ­āļĄāļđāļĨāļ—āļĩāđˆāļ•āđ‰āļ­āļ‡āļāļēāļĢ
rate_limit_exceeded 429 āđ€āļāļīāļ™āļˆāļģāļ™āļ§āļ™ requests āļ—āļĩāđˆāļāļģāļŦāļ™āļ”
internal_error 500 āđ€āļāļīāļ”āļ‚āđ‰āļ­āļœāļīāļ”āļžāļĨāļēāļ”āļ āļēāļĒāđƒāļ™āđ€āļ‹āļīāļĢāđŒāļŸāđ€āļ§āļ­āļĢāđŒ

🔒 Security Best Practices

🔑 āđ€āļāđ‡āļš API Secret āđƒāļŦāđ‰āļ›āļĨāļ­āļ”āļ āļąāļĒ

āļ­āļĒāđˆāļēāđ€āļāđ‡āļš secret āđƒāļ™ code āļŦāļĢāļ·āļ­ version control āđƒāļŠāđ‰ environment variables

🔒 āđƒāļŠāđ‰ HTTPS āđ€āļŠāļĄāļ­

āļ­āļĒāđˆāļēāļŠāđˆāļ‡ API requests āļœāđˆāļēāļ™ HTTP

🔄 āđƒāļŠāđ‰ Idempotency Keys

āļŠāđˆāļ§āļĒāļ›āđ‰āļ­āļ‡āļāļąāļ™āļāļēāļĢāļŠāļĢāđ‰āļēāļ‡āļ‚āđ‰āļ­āļĄāļđāļĨāļ‹āđ‰āļģ

⏱ïļ Handle Rate Limits

āļ•āļĢāļ§āļˆāļŠāļ­āļš response headers āđāļĨāļ° implement exponential backoff

ðŸ’Ą Code Examples

JavaScript Example

// 1. Get JWT Token
async function getAccessToken() {
  const response = await fetch('/api/v1/auth/token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      apiKey: 'your-api-key',
      apiSecret: 'your-api-secret'
    })
  });
  const data = await response.json();
  return data.data.accessToken;
}

// 2. Create Customer
async function createCustomer(token, customerData) {
  const response = await fetch('/api/v1/customers/upsert', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${token}`,
      'Idempotency-Key': `create-${Date.now()}`
    },
    body: JSON.stringify(customerData)
  });
  return response.json();
}

// 3. List Customers
async function listCustomers(token, page = 1, limit = 20) {
  const response = await fetch(
    `/api/v1/customers?page=${page}&limit=${limit}`,
    {
      headers: { 'Authorization': `Bearer ${token}` }
    }
  );
  return response.json();
}

Rate Limiting Example

async function callAPIWithRetry(url, options, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    const response = await fetch(url, options);
    
    // Check rate limit headers
    const remaining = parseInt(response.headers.get('X-RateLimit-Remaining'));
    console.log(`API calls remaining: ${remaining}`);
    
    if (response.status === 429) {
      const retryAfter = parseInt(response.headers.get('Retry-After'));
      console.log(`Rate limited. Retry after ${retryAfter} seconds`);
      await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
      continue;
    }
    
    return response;
  }
  
  throw new Error('Max retries exceeded');
}