PleasureStock API v1.0

Complete B2B Integration API Documentation

🤖 AI-Optimized Version Single page format for LLMs and automation

🚀 Quick Start Guide

Base URL for API calls: https://pleasurestock.com/api/v1
⚠️ This is not a web page - use this URL in your code for API requests

Available APIs

Rate Limits

Endpoint Type Requests/Hour Requests/Minute Burst Limit
Standard API 1,000 100 10/sec
External API 5,000 200 20/sec
Smart Reordering 100 10 2/sec

🔐 Authentication

Getting Your API Key

  1. Login to PleasureStock at https://pleasurestock.com
  2. Navigate to Settings → API Keys
  3. Click "Generate New Key"
  4. Save your key immediately (shown only once!)

Authentication Methods

Method 1: X-API-Key Header (Standard API)

HTTP Header
X-API-Key: pk_live_a1b2c3d4e5f6g7h8i9j0

Method 2: Bearer Token (External API)

HTTP Header
Authorization: Bearer pk_live_a1b2c3d4e5f6g7h8i9j0
Security Notice: Never expose your API key in client-side code or public repositories.

📦 Standard API Endpoints

GET /api/v1/products Stable

Retrieve product catalog with filtering and pagination.

Query Parameters

Parameter Type Required Description
page integer No Page number (default: 1)
limit integer No Items per page (max: 1000, default: 100)
supplier_id integer No Filter by supplier ID

Response Example

200 OK
{
  "success": true,
  "data": [
    {
      "internal_id": "pl_1234567890",
      "name": "Premium Silicone Vibrator",
      "sku": "VIB-001",
      "price": "49.99",
      "currency": "EUR",
      "supplier_id": 12,
      "created_at": "2024-01-15T10:30:00Z",
      "updated_at": "2024-03-20T14:45:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 100,
    "total": 1250,
    "pages": 13
  }
}
POST /api/v1/sales Stable

Submit sales data for Smart Reordering AI predictions and inventory tracking.

✨ Updated 2025-11-03: Now supports both UUID and ps_id formats for product identification!

Request Body

JSON
{
  "sales": [
    {
      "internal_id": "ps_uypjz2vraa",
      "date": "2025-11-03",
      "quantity": 15,
      "stock_on_hand": 120
    },
    {
      "internal_id": "b421eb2c-e1ee-4537-9c19-056d63a337c4",
      "date": "2025-11-03",
      "quantity": 8,
      "stock_on_hand": 45
    }
  ]
}

Request Parameters

Field Type Required Format Example
internal_id string ✅ Yes UUID or ps_id "ps_uypjz2vraa" or
"b421eb2c-e1ee-4537-9c19-056d63a337c4"
date string ✅ Yes YYYY-MM-DD "2025-11-03"
quantity integer ✅ Yes ≥ 0 15
stock_on_hand integer ❌ No ≥ 0 120

Validation Rules

  • internal_id accepts two formats:
    • UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx (36 characters)
    • ps_id: ps_XXXXXXXXXX (starts with "ps_")
  • date must be valid ISO date (YYYY-MM-DD format)
  • quantity must be non-negative integer
  • stock_on_hand is optional, non-negative integer
  • Array sales can contain up to 1000 records per request

Success Response

200 OK
{
  "success": true,
  "message": "Sales data submitted successfully",
  "processed": 2
}

Error Response

400 Bad Request
{
  "error": "Validation errors",
  "errors": [
    {
      "index": 0,
      "error": "Invalid internal_id format",
      "expected": "UUID (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) or ps_id (ps_XXXXXXXXXX)",
      "received": "invalid_id_123"
    }
  ],
  "processed": 0
}
💡 How to find product internal_id:
1. Login to PleasureStock
2. Go to Products section
3. Find your product by SKU
4. Column "PleasureStock ID" shows the internal_id

What Happens After Submission?

  1. ✅ Sales data is stored in PleasureStock
  2. 🤖 AI automatically calculates Smart Reordering recommendations (once daily)
  3. 📊 View recommendations at: Cart → Smart Reordering tab
  4. 🎯 See recommended quantities, current stock, and forecast accuracy

Best Practices

  • 📅 Frequency: Send data daily (minimum) or every 2-4 hours (optimal)
  • 📊 Historical Data: Submit past 30-90 days for better AI predictions
  • 📦 Batch Size: Up to 1000 records per request
  • 🎯 Accuracy: Always include stock_on_hand for best results
🌍 Idempotency (World-Class Best Practice):
You can safely send the same data multiple times - the system automatically deduplicates by date.

Example: If you send data for 2025-11-03 twice, the system will aggregate:
  • quantitySUM (total sales for the day)
  • stock_on_handMAX (highest stock level = total across warehouses)
This design follows Amazon MWS and Shopify API patterns.

Multiple Warehouses Support

If you have multiple warehouses, send data from each warehouse separately. The system will aggregate automatically:

Multiple Warehouses Example
{
  "sales": [
    {
      "internal_id": "ps_abc123",
      "date": "2025-11-03",
      "quantity": 10,          // Warehouse A sales
      "stock_on_hand": 500     // Warehouse A stock
    },
    {
      "internal_id": "ps_abc123",  // Same product, different warehouse
      "date": "2025-11-03",
      "quantity": 5,           // Warehouse B sales
      "stock_on_hand": 300     // Warehouse B stock
    }
  ]
}

Result: System aggregates to quantity: 15 (total sales) and stock_on_hand: 500 (max = total stock across all warehouses).

Out-of-Stock Days

When a product is out of stock, send stock_on_hand: 0. The AI will:

  • ✅ Exclude these days from average sales calculations
  • ✅ Mark them as OOS (Out-of-Stock) periods
  • ✅ Provide more accurate forecasts by ignoring zero-sales due to stockouts
Out-of-Stock Example
{
  "sales": [{
    "internal_id": "ps_abc123",
    "date": "2025-11-03",
    "quantity": 0,           // No sales possible
    "stock_on_hand": 0       // ⚠️ Out of stock!
  }]
}
GET /api/v1/smart-reordering Stable

Get AI-powered inventory recommendations based on sales history.

Query Parameters

Parameter Type Required Description
date string No Target date for predictions (default: today)
Note: Requires sales data submission for accurate predictions.
GET /api/v1/currency/convert-to-try Stable

Convert prices to Turkish Lira with real-time exchange rates.

Query Parameters

Parameter Type Required Description
amount number Yes Amount to convert
currency string Yes Source currency (EUR, USD, GBP)

🔗 External B2B Integration API

Authentication: External API uses Bearer token authentication.
Base URL: https://pleasurestock.com/api/v1/external
Rate Limit: 5000 requests/hour per API key
POST /api/v1/external/orders Stable

Create new orders in PleasureStock system. Items are automatically grouped by supplier.

Request Body

JSON
{
  "items": [
    {
      "ps_id": "ps_1234567890",
      "quantity": 10,
      "customPrice": 25.50  // optional, uses product price if not provided
    },
    {
      "ps_id": "ps_0987654321",
      "quantity": 5
    }
  ],
  "externalOrderId": "ERP-2025-001",  // your internal reference
  "comment": "Urgent order for customer ABC"
}

Response Example

200 OK
{
  "success": true,
  "data": {
    "orders": [
      {
        "orderNumber": "ORD-2025-000123",
        "deliveryId": "PS-2025-0114",
        "supplierId": 12,
        "status": "created",
        "totalAmount": 255.00,
        "currency": "USD",
        "items": 1,
        "createdAt": "2025-01-14T10:00:00Z"
      },
      {
        "orderNumber": "ORD-2025-000124",
        "deliveryId": "PS-2025-0115",
        "supplierId": 15,
        "status": "created",
        "totalAmount": 125.00,
        "currency": "USD",
        "items": 1,
        "createdAt": "2025-01-14T10:00:00Z"
      }
    ],
    "totalOrders": 2,
    "totalAmount": 380.00
  }
}
Important: Items are automatically grouped by supplier. One API call may create multiple orders.
POST /api/v1/external/smart-reorder Stable

Submit comprehensive sales data for AI-powered reordering recommendations.

Request Body

JSON
{
  "products": [
    {
      "ps_id": "ps_1234567890",
      "quantity": 15,
      "current_stock": 85,
      "sales_history": [5, 8, 12, 6, 9, 11, 7]
    }
  ]
}

Validation Requirements

  • ps_id must start with "ps_" prefix
  • quantity must be non-negative number
  • current_stock must be non-negative number
  • sales_history must contain at least 7 days of data
GET /api/v1/external/orders Stable

Retrieve all orders created by your API key with filtering options.

Query Parameters

Parameter Type Required Description
status string No Filter by status (created, part_paid, paid, on_the_way, accepted)
limit integer No Results per page (default: 20)
offset integer No Skip records (default: 0)
GET /api/v1/external/orders/{orderNumber} Stable

Get detailed information about a specific order.

PUT /api/v1/external/orders/{orderNumber}/status Stable

Update order status in the workflow.

Request Body

JSON
{
  "status": "paid",
  "externalOrderId": "EXT-123456",
  "comment": "Payment confirmed"
}

Status Workflow

Order Status Lifecycle:
created (System) → part_paid (External API) → paid (External API) → on_the_way (External API) → accepted (External API)
Status Set By Description Notifications
created System Order created, awaiting payment None
part_paid External API Partial payment received Email to supplier
paid External API Full payment confirmed Email to supplier
on_the_way External API Shipment dispatched Email to buyer
accepted External API Goods received by buyer Email to supplier
POST /api/v1/external/webhook Stable

Receive webhook notifications for order events.

Webhook Events

  • order.confirmed - Order confirmed in system
  • order.status_changed - Order status updated

🔔 Webhooks

Configuration

Configure webhook endpoints in Settings → API Keys → Webhook Configuration

Webhook Events

Event Trigger Payload
order.created New order created via API Full order details with items
order.status_changed Order status updated Order with old/new status
order.cancelled Order cancelled Order details with cancellation reason

Webhook Security

All webhook requests include HMAC-SHA256 signature for verification:

Headers
X-Webhook-Signature: sha256=4f8b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b
X-Webhook-Timestamp: 1736850600

Webhook Payload Examples

order.created Event

POST to your endpoint
{
  "event": "order.created",
  "timestamp": "2025-01-14T10:00:00Z",
  "data": {
    "orderId": "550e8400-e29b-41d4-a716-446655440000",
    "orderNumber": "ORD-2025-000123",
    "deliveryId": "PS-2025-0114",
    "status": "created",
    "supplierId": "550e8400-e29b-41d4-a716-446655440001",
    "totalAmount": 255.00,
    "currency": "USD",
    "items": [
      {
        "ps_id": "ps_1234567890",
        "quantity": 10,
        "unitPrice": 25.50,
        "totalPrice": 255.00
      }
    ],
    "externalOrderId": "ERP-2025-001",
    "createdAt": "2025-01-14T10:00:00Z"
  }
}

order.status_changed Event

POST to your endpoint
{
  "event": "order.status_changed",
  "timestamp": "2025-01-14T11:00:00Z",
  "data": {
    "orderId": "550e8400-e29b-41d4-a716-446655440000",
    "orderNumber": "ORD-2025-000123",
    "oldStatus": "created",
    "newStatus": "paid",
    "changedBy": "external_api",
    "comment": "Payment confirmed via bank transfer",
    "changedAt": "2025-01-14T11:00:00Z"
  }
}

Webhook Retry Mechanism

Automatic Retries: Failed webhook deliveries are retried with exponential backoff:
• 1st retry: After 2 seconds
• 2nd retry: After 4 seconds
• 3rd retry: After 8 seconds
• Timeout: 10 seconds per request
• Failed webhooks are queued for manual retry

⚠️ Error Handling

Error Response Format

Error Response
{
  "success": false,
  "error": "Invalid request",
  "message": "The request payload is invalid",
  "details": ["Missing required field: internal_id"]
}

HTTP Status Codes

Code Description Common Causes
200 Success Request processed successfully
400 Bad Request Invalid parameters, validation errors
401 Unauthorized Missing or invalid API key
403 Forbidden Insufficient permissions
404 Not Found Resource doesn't exist
429 Too Many Requests Rate limit exceeded
500 Internal Server Error Server-side error

💻 Code Examples

cURL

Get Products
curl -X GET "https://pleasurestock.com/api/v1/products?limit=10" \
  -H "X-API-Key: pk_live_your_api_key_here"

Python

Create Order via External API
import requests
import hashlib
import hmac
import time

class PleasureStockAPI:
    def __init__(self, api_key, webhook_secret=None):
        self.api_key = api_key
        self.webhook_secret = webhook_secret
        self.base_url = "https://pleasurestock.com/api/v1"
    
    def create_order(self, items, external_order_id=None, comment=None):
        """Create a new order in PleasureStock"""
        headers = {
            "Authorization": f"Bearer {self.api_key}",
            "Content-Type": "application/json"
        }
        
        payload = {
            "items": items,
            "externalOrderId": external_order_id,
            "comment": comment
        }
        
        response = requests.post(
            f"{self.base_url}/external/orders",
            json=payload,
            headers=headers
        )
        
        if response.status_code == 200:
            return response.json()
        else:
            raise Exception(f"API Error: {response.text}")
    
    def update_order_status(self, order_number, status, comment=None):
        """Update order status"""
        headers = {
            "Authorization": f"Bearer {self.api_key}",
            "Content-Type": "application/json"
        }
        
        payload = {"status": status}
        if comment:
            payload["comment"] = comment
        
        response = requests.put(
            f"{self.base_url}/external/orders/{order_number}/status",
            json=payload,
            headers=headers
        )
        
        return response.json()
    
    def verify_webhook(self, signature, timestamp, body):
        """Verify webhook signature"""
        if not self.webhook_secret:
            return False
        
        message = f"{timestamp}.{body}"
        expected = hmac.new(
            self.webhook_secret.encode(),
            message.encode(),
            hashlib.sha256
        ).hexdigest()
        
        return f"sha256={expected}" == signature

# Example usage
api = PleasureStockAPI("pk_live_your_api_key_here")

# Create order
order = api.create_order(
    items=[
        {"ps_id": "ps_1234567890", "quantity": 10, "customPrice": 25.50},
        {"ps_id": "ps_0987654321", "quantity": 5}
    ],
    external_order_id="ERP-2025-001",
    comment="Urgent order"
)

print(f"Created {order['data']['totalOrders']} orders")
for o in order['data']['orders']:
    print(f"  - {o['orderNumber']}: ${o['totalAmount']}")

# Update status to paid
api.update_order_status(
    order['data']['orders'][0]['orderNumber'],
    "paid",
    "Payment confirmed"
)

Node.js

External API - Get Orders
const axios = require('axios');

class PleasureStockAPI {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.baseURL = 'https://pleasurestock.com/api/v1';
  }

  async getOrders(status = null) {
    try {
      const params = status ? { status } : {};
      
      const response = await axios.get(
        `${this.baseURL}/external/orders`,
        {
          headers: {
            'Authorization': `Bearer ${this.apiKey}`
          },
          params
        }
      );
      
      return response.data;
    } catch (error) {
      console.error('API Error:', error.response?.data || error.message);
      throw error;
    }
  }

  async updateOrderStatus(orderNumber, status, comment = '') {
    try {
      const response = await axios.put(
        `${this.baseURL}/external/orders/${orderNumber}/status`,
        { status, comment },
        {
          headers: {
            'Authorization': `Bearer ${this.apiKey}`,
            'Content-Type': 'application/json'
          }
        }
      );
      
      return response.data;
    } catch (error) {
      console.error('API Error:', error.response?.data || error.message);
      throw error;
    }
  }
}

// Usage
const api = new PleasureStockAPI('pk_live_your_api_key_here');

// Get pending orders
api.getOrders('pending')
  .then(orders => {
    console.log(`Found ${orders.data.orders.length} pending orders`);
  });

// Update order status
api.updateOrderStatus('ORD-2024-001234', 'paid', 'Payment confirmed')
  .then(result => {
    console.log('Order updated:', result);
  });

🎮 API Playground

Enter your API key to test endpoints directly from this page.

Test API Connection