Commercy Supplier-Reseller System API

Professional, versioned API with compression and enhanced security

Quick Start

Overview

🚀

Professional Structure

Versioned API with `/api/v1/` endpoints, compression, and enhanced CORS configuration.

Performance Optimized

60-80% response compression, preflight caching, and optimized headers.

🔒

Secure & Scalable

JWT authentication, rate limiting, and industry-standard security practices.

Quick Start

Base URLs

# Development
http://localhost:3001/api/v1

# Production
https://your-domain.com/api/v1

Authentication

// Login to get JWT token
const response = await fetch('http://localhost:3001/api/v1/auth/login', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    email: 'user@example.com',
    password: 'password'
  })
});

const { token } = await response.json();

// Use token in subsequent requests
const apiResponse = await fetch('http://localhost:3001/api/v1/orders', {
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  }
});

API Status

Current Status

Check if the API is running and accessible

API Endpoints

Authentication

POST /api/v1/auth/login

User login to get JWT token

{
  "email": "user@example.com",
  "password": "password"
}
POST /api/v1/auth/register

User registration

GET /api/v1/auth/profile

Get user profile (requires authentication)

Orders

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

Get all orders with pagination

POST /api/v1/orders

Create a new order (supports both old and new field names)

{
  "customerName": "John Doe",
  "customerPhone": "+1234567890",        // New field name
  "customerPhone1": "+1234567890",       // Old field name (also supported)
  "customerPhone2": "+1234567891",
  "customerAddress": "123 Main St",      // New field name
  "address": "123 Main St",              // Old field name (also supported)
  "customerCity": "Tunis",               // New field name
  "ville": "Tunis",                      // Old field name (also supported)
  "customerGovernorate": "Tunis",        // New field name
  "gouvernaurat": "Tunis",               // Old field name (also supported)
           "customerZipCode": "1000",          // Optional zip code
  "notes": "Special delivery instructions", // Optional notes
  "source": "manual",                    // Optional, must be one of: manual, scraped, api, converty, phone_call, whatsapp, facebook_page, instagram, sur_place, autre (defaults to "manual")
  "products": [
    {
      "productId": 1,
      "quantity": 2,
      "price": 99.99                     // New field name
    },
    {
      "productId": 2,
      "quantity": 1,
      "unitPrice": 49.99                 // Old field name (also supported)
    }
  ]
}

Backward Compatibility:

  • Phone: Supports both customerPhone and customerPhone1
  • Address: Supports both customerAddress and address
  • City: Supports both customerCity and ville
  • Governorate: Supports both customerGovernorate and gouvernaurat
  • Price: Supports both price and unitPrice
  • New Fields: customerZipCode, notes, and source are optional
  • Source Values: source must be one of: manual, scraped, api, converty, phone_call, whatsapp, facebook_page, instagram, sur_place, autre

Validation Requirements:

  • customerName: Required - Customer's full name
  • customerPhone OR customerPhone1: Required - Primary phone number
  • customerPhone2: Optional - Secondary phone number
  • customerAddress OR address: Required - Customer's address
  • customerCity OR ville: Required - Customer's city
  • customerGovernorate OR gouvernaurat: Required - Customer's governorate
  • customerZipCode: Optional - Customer's zip code
  • notes: Optional - Additional order notes
  • source: Optional - Order source (must be one of: manual, scraped, api, converty, phone_call, whatsapp, facebook_page, instagram, sur_place, autre, defaults to "manual")
  • products: Array with 1-2 products (each with productId, quantity, price/unitPrice)

Source Values:

  • manual: Manually created order (default)
  • scraped: Order from web scraping
  • api: Order from external API
  • converty: Order from Converty integration
  • phone_call: Order from phone call
  • whatsapp: Order from WhatsApp
  • facebook_page: Order from Facebook page
  • instagram: Order from Instagram
  • sur_place: Order created on-site
  • autre: Other source

Response:

{
  "success": true,
  "message": "Order created successfully",
  "orderNumber": "ORD-1755436083209-123",
  "orderStatus": "pending",
  "order": {
    "id": 123,
    "orderNumber": "ORD-1755436083209-123",
    "status": "pending",
    "total": 249.97,
    "customerName": "John Doe",
    "customerPhone": "+1234567890",
    "customerPhone2": "+1234567891",
    "customerAddress": "123 Main St",
    "customerCity": "Tunis",
    "customerGovernorate": "Tunis",
               "customerZipCode": "1000",
    "notes": "Special delivery instructions",
    "source": "manual",
    "barcode": "ORD-1755436083209-123"
  }
}
PUT /api/v1/orders/:id

Update order details

PUT /api/v1/orders/:id/status

Update order status with delivery integration

{
  "status": "confirmed",
  "deliveryCompany": "fiabilo"
}
PUT /api/v1/orders/:id/payment

Update order payment information

{
  "paymentStatus": "paid",
  "paymentMethod": "cash",
  "paidAmount": 199.98,
  "paymentNotes": "Payment received"
}
PUT /api/v1/orders/:id/delivery

Update order delivery information

{
  "deliveryCompanyId": 1,
  "deliveryNotes": "Handle with care",
  "trackingNumber": "TRK123456",
  "estimatedDeliveryDate": "2024-01-20"
}
PUT /api/v1/orders/:id/items

Update order items

{
  "items": [
    {
      "productId": 1,
      "quantity": 3,
      "unitPrice": 99.99,
      "notes": "Updated item"
    }
  ]
}
PUT /api/v1/orders/:id/cancel

Cancel order

{
  "cancellationReason": "Customer request",
  "refundAmount": 199.98
}
DELETE /api/v1/orders/:id

Delete order (cannot delete if in delivery)

DELETE /api/v1/orders/:id/barcode

Remove barcode from order

Products

GET /api/v1/products?search=keyword

Get products with search and pagination

POST /api/v1/products

Create a new product

PUT /api/v1/products/:id

Update product details

PATCH /api/v1/products/:id/stock

Update product stock only

{
  "stockQuantity": 200,
  "minQuantity": 15,
  "maxQuantity": 600,
  "stockNotes": "Stock updated from supplier"
}
PATCH /api/v1/products/:id/pricing

Update product pricing only

{
  "price": 89.99,
  "costPrice": 45.00,
  "pricingNotes": "Price updated due to supplier discount"
}
PATCH /api/v1/products/bulk-update

Bulk update multiple products

{
  "productIds": [1, 2, 3],
  "updates": {
    "category": "Electronics",
    "brand": "New Brand",
    "isActive": true,
    "price": 89.99,
    "stockQuantity": 200
  }
}
DELETE /api/v1/products/:id

Delete product (cannot delete if used in orders)

DELETE /api/v1/products/bulk-delete

Bulk delete multiple products

{
  "productIds": [1, 2, 3],
  "forceDelete": false
}

Resellers

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

Get all resellers with pagination

POST /api/v1/resellers

Create a new reseller

PUT /api/v1/resellers/:id

Update reseller details

PATCH /api/v1/resellers/:id/status

Update reseller status

{
  "isActive": true,
  "statusNotes": "Reseller activated"
}
PATCH /api/v1/resellers/:id/credit

Update reseller credit limit

{
  "creditLimit": 7500.00,
  "creditNotes": "Credit limit increased"
}
PATCH /api/v1/resellers/:id/payment-terms

Update reseller payment terms

{
  "paymentTerms": "Net 45",
  "paymentNotes": "Payment terms updated"
}
PATCH /api/v1/resellers/bulk-update

Bulk update multiple resellers

{
  "resellerIds": [1, 2, 3],
  "updates": {
    "businessType": "company",
    "isActive": true,
    "creditLimit": 10000.00,
    "paymentTerms": "Net 30"
  }
}
DELETE /api/v1/resellers/:id

Delete reseller (cannot delete if has outstanding balance)

DELETE /api/v1/resellers/bulk-delete

Bulk delete multiple resellers

{
  "resellerIds": [1, 2, 3],
  "forceDelete": false
}

Suppliers

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

Get all suppliers with pagination

POST /api/v1/suppliers

Create a new supplier

PUT /api/v1/suppliers/:id

Update supplier details

PATCH /api/v1/suppliers/:id/status

Update supplier status

{
  "isActive": true,
  "statusNotes": "Supplier activated"
}
PATCH /api/v1/suppliers/:id/business

Update supplier business information

{
  "taxId": "TAX123456",
  "registrationNumber": "REG123456",
  "businessType": "corporation",
  "businessNotes": "Business info updated"
}
PATCH /api/v1/suppliers/:id/contact

Update supplier contact information

{
  "contactPersonName": "New Contact",
  "contactPersonEmail": "newcontact@example.com",
  "contactPersonPhone": "+1234567890",
  "contactNotes": "Contact info updated"
}
PATCH /api/v1/suppliers/bulk-update

Bulk update multiple suppliers

{
  "supplierIds": [1, 2, 3],
  "updates": {
    "businessType": "corporation",
    "isActive": true,
    "paymentTerms": "Net 45",
    "creditLimit": 15000.00
  }
}
DELETE /api/v1/suppliers/:id

Delete supplier (cannot delete if has active relationships)

DELETE /api/v1/suppliers/bulk-delete

Bulk delete multiple suppliers

{
  "supplierIds": [1, 2, 3],
  "forceDelete": false
}

Payments

GET /api/v1/payments/summary

Get payment summary

GET /api/v1/payments/history

Get payment history

Code Examples

JavaScript/Node.js

const api = new CommercyAPI({
  baseURL: 'http://localhost:3001',
  apiVersion: 'v1'
});

// Login
const loginResult = await api.login('user@example.com', 'password');

// Get orders
const orders = await api.getOrders({ limit: 10, page: 1 });

// Create order
const newOrder = await api.createOrder({
  customerName: 'John Doe',
  products: [{ productId: 1, quantity: 2 }]
});

Python

import requests

class CommercyAPI:
    def __init__(self, base_url, token):
        self.base_url = f"{base_url}/api/v1"
        self.headers = {
            'Authorization': f'Bearer {token}',
            'Content-Type': 'application/json'
        }
    
    def get_orders(self, params=None):
        response = requests.get(
            f"{self.base_url}/orders",
            headers=self.headers,
            params=params
        )
        return response.json()

# Usage
api = CommercyAPI('http://localhost:3001', 'your-token')
orders = api.get_orders({'limit': 10, 'page': 1})

SDK & Tools

JavaScript SDK

Complete SDK with all endpoints and error handling

Postman Collection

Ready-to-use Postman collection for testing

Examples

Complete examples and usage patterns

Response Format

Standard Response

{
  "success": true,
  "data": {
    "id": 123,
    "customerName": "John Doe",
    "status": "pending",
    "createdAt": "2024-01-15T10:30:00.000Z"
  },
  "message": "Order created successfully",
  "timestamp": "2024-01-15T10:30:00.000Z"
}

Paginated Response

{
  "success": true,
  "data": [
    {
      "id": 1,
      "customerName": "John Doe",
      "status": "pending"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 10,
    "total": 100,
    "totalPages": 10,
    "hasNext": true,
    "hasPrev": false
  },
  "timestamp": "2024-01-15T10:30:00.000Z"
}

Error Handling

HTTP Status Codes

200 Success
201 Created
400 Bad Request
401 Unauthorized
404 Not Found
429 Rate Limited
500 Server Error

Error Response Format

{
  "success": false,
  "error": "Validation error",
  "message": "Invalid input data",
  "timestamp": "2024-01-15T10:30:00.000Z",
  "details": {
    "field": "email",
    "message": "Email is required"
  }
}

Support & Resources

Getting Help

  • • Email: api-support@commercy.tn
  • • Discord: Join our developer community
  • • GitHub: Create an issue on our repository
  • • Documentation: Complete API reference

Performance Tips

  • • Use pagination for large datasets
  • • Implement proper error handling
  • • Cache frequently accessed data
  • • Use compression for faster responses

Troubleshooting

Common Issues

"Invalid Date" in Tables

This usually occurs when date fields are not properly formatted. Ensure dates are sent in ISO format: YYYY-MM-DDTHH:mm:ss.sssZ

Validation Errors

Check that all required fields are provided and use the correct field names (old or new format supported).

Authentication Issues

Ensure you're sending a valid JWT token in the Authorization header: Bearer YOUR_TOKEN

Quick Fixes

Date Formatting

Use new Date().toISOString() for proper date formatting in JavaScript.

Field Names

Both old and new field names are supported. Use whichever format your frontend is already using.

API Version

Always use /api/v1/ endpoints for the latest features and backward compatibility.