External API Setup
Mock external systems using Cloudflare Workers and D1 database for testing NetSuite integrations.
This worker now also includes mock endpoints for Accounting, Supplier Catalog, Procurement, and Shopify fulfillment updates used by the remaining integration test cases.
Architecture Overview
INTEGRATION TEST ENVIRONMENT
===============================================================================
NetSuite Cloudflare Worker D1 Database
+-------------+ +------------------+ +----------+
| | PUSH OUT | | | |
| Sales Order | ---------------> | POST /api/orders | ---------> | orders |
| (approved) | JSON payload | | INSERT | |
| | +------------------+ +----------+
| |
| | PULL IN +------------------+ +----------+
| Exchange | <--------------- | GET /api/rates | <--------- | rates |
| Rates | JSON response | | SELECT | |
+-------------+ +------------------+ +----------+
Auth: X-API-Key header with static token
Cloudflare Worker Setup
Prerequisites
# Install Wrangler CLI
npm install -g wrangler
# Login to Cloudflare
wrangler login
# Use the repo worker project
cd workers/quickmart-warehouse-api
wrangler.toml Configuration
name = "quickmart-warehouse-api"
main = "src/index.js"
compatibility_date = "2026-02-06"
workers_dev = true
# D1 Database binding
[[d1_databases]]
binding = "DB"
database_name = "quickmart-warehouse"
database_id = "REPLACE_WITH_DATABASE_ID"
# Environment variables (secrets set via wrangler secret)
[vars]
API_KEY = "qm-warehouse-test-key-2026" # For dev only, use secrets in prod
Create D1 Database
# Create the database
wrangler d1 create quickmart-warehouse
# Copy the database_id to wrangler.toml
Database Schema
schema.sql
Schema lives in workers/quickmart-warehouse-api/schema.sql:
-- ============================================================================
-- QuickMart Warehouse Database Schema
-- ============================================================================
PRAGMA foreign_keys = ON;
-- Orders received from NetSuite
CREATE TABLE IF NOT EXISTS orders (
id INTEGER PRIMARY KEY AUTOINCREMENT,
netsuite_id INTEGER NOT NULL UNIQUE,
order_number TEXT NOT NULL,
customer_name TEXT,
ship_address TEXT,
priority INTEGER DEFAULT 0,
status TEXT DEFAULT 'pending' CHECK(status IN ('pending', 'picking', 'packed', 'shipped', 'cancelled')),
created_at TEXT DEFAULT (datetime('now')),
updated_at TEXT DEFAULT (datetime('now')),
completed_at TEXT
);
-- Order line items
CREATE TABLE IF NOT EXISTS order_lines (
id INTEGER PRIMARY KEY AUTOINCREMENT,
order_id INTEGER NOT NULL REFERENCES orders(id) ON DELETE CASCADE,
item_sku TEXT,
item_name TEXT,
quantity INTEGER NOT NULL,
location TEXT,
picked_qty INTEGER DEFAULT 0,
status TEXT DEFAULT 'pending' CHECK(status IN ('pending', 'picked', 'packed'))
);
-- Exchange rates (for Pull In testing)
CREATE TABLE IF NOT EXISTS exchange_rates (
id INTEGER PRIMARY KEY AUTOINCREMENT,
base_currency TEXT DEFAULT 'USD',
target_currency TEXT NOT NULL,
rate REAL NOT NULL,
updated_at TEXT DEFAULT (datetime('now'))
);
-- Integration log (audit trail)
CREATE TABLE IF NOT EXISTS integration_log (
id INTEGER PRIMARY KEY AUTOINCREMENT,
direction TEXT CHECK(direction IN ('inbound', 'outbound')),
endpoint TEXT,
method TEXT,
payload TEXT,
response TEXT,
status_code INTEGER,
created_at TEXT DEFAULT (datetime('now'))
);
-- Seed exchange rates
INSERT INTO exchange_rates (target_currency, rate) VALUES
('EUR', 0.92),
('GBP', 0.79),
('SGD', 1.35),
('IDR', 15650);
-- Create indexes
CREATE INDEX IF NOT EXISTS idx_orders_status ON orders(status);
CREATE INDEX IF NOT EXISTS idx_orders_netsuite_id ON orders(netsuite_id);
CREATE INDEX IF NOT EXISTS idx_order_lines_order_id ON order_lines(order_id);
Apply Schema
wrangler d1 execute quickmart-warehouse --file=./schema.sql
Worker Source Code
src/index.js
The worker source lives in workers/quickmart-warehouse-api/src/index.js and is the canonical implementation. It includes the routes below:
POST /api/ordersGET /api/ordersGET /api/orders/:idPOST /api/orders/:id/pickPOST /api/orders/:id/shipGET /api/ratesGET /api/stock/:skuPOST /api/invoicesGET /api/invoicesGET /api/catalogPOST /api/requestsPUT /api/shopify/orders/:id.json
Deployment
# Deploy to Cloudflare
wrangler deploy
# Set secret API key for production
wrangler secret put API_KEY
# Enter: your-secure-api-key-here
# Test the deployment
curl -X GET "https://quickmart-warehouse-api.appsvein.workers.dev/api/rates" \
-H "X-API-Key: qm-warehouse-test-key-2026"
API Reference
Authentication
All requests require the X-API-Key header:
X-API-Key: qm-warehouse-test-key-2026
Endpoints
POST /api/orders
Receive order from NetSuite (Push Out pattern).
Request:
{
"nsInternalId": 12345,
"orderId": "SO-00567",
"customer": "ABC Corporation",
"shipAddress": "123 Main St, Springfield, IL 62701",
"priority": true,
"lines": [
{
"item": "A4 Printer Paper",
"sku": "PAPER-A4",
"quantity": 20,
"location": "Main Warehouse"
},
{
"item": "HP Ink Cartridge",
"sku": "INK-HP-BLACK",
"quantity": 5,
"location": "Main Warehouse"
}
]
}
Response (201):
{
"success": true,
"message": "Order received and queued for fulfillment",
"warehouse_id": 42,
"order_number": "SO-00567",
"status": "pending",
"estimated_ship_date": "2024-03-16"
}
GET /api/orders
List orders with optional filtering.
Query Parameters:
status- Filter by status (pending, picking, packed, shipped)limit- Max results (default: 50)
Response:
{
"success": true,
"count": 2,
"orders": [
{
"id": 42,
"netsuite_id": 12345,
"order_number": "SO-00567",
"customer_name": "ABC Corporation",
"priority": 1,
"status": "pending",
"created_at": "2024-03-15T10:30:00Z"
}
]
}
GET /api/orders/:id
Get order details with lines.
Response:
{
"success": true,
"order": {
"id": 42,
"netsuite_id": 12345,
"order_number": "SO-00567",
"customer_name": "ABC Corporation",
"ship_address": "123 Main St, Springfield, IL 62701",
"priority": 1,
"status": "pending",
"created_at": "2024-03-15T10:30:00Z",
"lines": [
{
"id": 1,
"item_sku": "PAPER-A4",
"item_name": "A4 Printer Paper",
"quantity": 20,
"location": "Main Warehouse",
"picked_qty": 0,
"status": "pending"
}
]
}
}
POST /api/orders/:id/ship
Mark order as shipped.
Request:
{
"trackingNumber": "FEDEX123456789"
}
Response:
{
"success": true,
"message": "Order shipped",
"order_id": 42,
"netsuite_id": 12345,
"tracking_number": "FEDEX123456789",
"carrier": "FedEx",
"shipped_at": "2024-03-16T14:30:00Z"
}
GET /api/rates
Get exchange rates (for Pull In pattern).
Response:
{
"success": true,
"base": "USD",
"date": "2024-03-15",
"rates": {
"EUR": 0.92,
"GBP": 0.79,
"SGD": 1.35,
"IDR": 15650
}
}
GET /api/stock/:sku
Get stock availability.
Response:
{
"success": true,
"sku": "PAPER-A4",
"inventory": {
"available": 150,
"on_hand": 200,
"on_order": 50,
"warehouse": "Main Warehouse"
},
"last_updated": "2024-03-15T10:00:00Z"
}
POST /api/invoices
Receive invoice batch for Accounting (Push Out pattern).
Request:
{
"invoices": [
{
"invoiceNumber": "INV-10045",
"customer": "ABC Corporation",
"amount": 1250.75,
"dueDate": "2026-02-28"
}
]
}
Response (200):
{
"success": true,
"received": 1,
"invoices": ["INV-10045"]
}
GET /api/invoices
List received invoices.
Query Parameters:
limit- Max results (default: 50)received_since- ISO date/time filter
GET /api/catalog
Supplier catalog feed (Pull In pattern).
Response:
{
"success": true,
"count": 2,
"items": [
{
"sku": "PAPER-A4",
"item_name": "A4 Printer Paper",
"description": "80gsm paper, 500 sheets",
"price": 12.5,
"currency": "USD",
"updated_at": "2026-02-06T08:26:00Z"
}
]
}
POST /api/requests
Receive approved PR payloads for Procurement (Push Out pattern).
Request:
{
"source": "NETSUITE",
"source_id": 9012,
"pr_number": "PR-2026-0142",
"total_amount": 3120.00,
"items": [
{ "item_id": 101, "item_name": "Paper A4", "quantity": 40, "unit_price": 12.5 }
]
}
Response (200):
{
"success": true,
"request_id": "REQ-ABC123",
"status": "received"
}
PUT /api/shopify/orders/:id.json
Mock Shopify fulfillment update (Push Out pattern).
Request:
{
"order": { "fulfillment_status": "fulfilled" }
}
Response (200):
{
"success": true,
"order_id": "SHOP-12345",
"fulfillment_status": "fulfilled"
}
Testing with cURL
# Set your worker URL
API_URL="https://quickmart-warehouse-api.appsvein.workers.dev"
API_KEY="qm-warehouse-test-key-2026"
# Test: Push order from "NetSuite"
curl -X POST "$API_URL/api/orders" \
-H "Content-Type: application/json" \
-H "X-API-Key: $API_KEY" \
-d '{
"nsInternalId": 12345,
"orderId": "SO-00567",
"customer": "ABC Corporation",
"priority": true,
"lines": [
{"item": "Paper A4", "sku": "PAPER-A4", "quantity": 20}
]
}'
# Test: List orders
curl "$API_URL/api/orders" -H "X-API-Key: $API_KEY"
# Test: Get exchange rates
curl "$API_URL/api/rates" -H "X-API-Key: $API_KEY"
# Test: Get stock
curl "$API_URL/api/stock/PAPER-A4" -H "X-API-Key: $API_KEY"
# Test: Push invoices to accounting
curl -X POST "$API_URL/api/invoices" \
-H "Content-Type: application/json" \
-H "X-API-Key: $API_KEY" \
-d '{"invoices":[{"invoiceNumber":"INV-10045","customer":"ABC Corporation","amount":1250.75,"dueDate":"2026-02-28"}]}'
# Test: Pull supplier catalog
curl "$API_URL/api/catalog" -H "X-API-Key: $API_KEY"
# Test: Push PR to procurement
curl -X POST "$API_URL/api/requests" \
-H "Content-Type: application/json" \
-H "X-API-Key: $API_KEY" \
-d '{"pr_number":"PR-2026-0142","total_amount":3120.00,"items":[{"item_id":101,"item_name":"Paper A4","quantity":40,"unit_price":12.5}]}'
# Test: Push fulfillment status to Shopify
curl -X PUT "$API_URL/api/shopify/orders/SHOP-12345.json" \
-H "Content-Type: application/json" \
-H "X-API-Key: $API_KEY" \
-d '{"order":{"fulfillment_status":"fulfilled"}}'
Next Steps
- Integration Test Cases → - See how NetSuite connects to this API
- SuiteScript Test Cases → - RESTlet and User Event scripts