A small Node.js Express API for creating Shopify customers, orders, and draft orders from a single request.
This repository contains a simple API server built with Express. It includes:
POST /api/create-orderto create a Shopify orderPOST /api/create-draft-orderto create a Shopify draft order- Customer lookup and creation by email
- Request validation for required fields
- Logging to console and
logs/app.log - Security middleware, rate limiting, CORS, and request logging
server.js: main application file- loads environment variables with
dotenv - configures Express with
helmet,cors,morgan, andexpress-rate-limit - validates required environment variables:
SHOPIFY_STOREandSHOPIFY_ACCESS_TOKEN - defines helper functions for Shopify requests and request body validation
- creates or finds a Shopify customer before creating an order or draft order
- writes logs to
logs/app.log
- loads environment variables with
package.json: project configuration and dependencieslogs/: automatically created directory for log output
- Install dependencies:
npm install- Create a
.envfile in the project root with the following values:
SHOPIFY_STORE=your-store.myshopify.com
SHOPIFY_ACCESS_TOKEN=shpat_xxxxxxxxxxxxxxxx
PORT=3000- Start the server:
npm start- Open your browser or API client to:
http://localhost:3000/Required values:
SHOPIFY_STORE: your Shopify store domain, for exampleyour-store.myshopify.comSHOPIFY_ACCESS_TOKEN: your store access tokenPORT: optional. Defaults to3000if not set
The API includes the following security features:
- Helmet.js — sets security HTTP headers
- CORS — allows requests from any origin (configurable)
- Rate Limiting — limits requests to 100 per 15 minutes per IP
- Request Validation — validates all required fields before processing
- Timeout Protection — 15 second timeout on all Shopify API requests
- Global Error Handler — catches and logs unhandled errors
The API logs all activity to both console and logs/app.log:
- Request details (endpoint, method)
- Customer operations (creation, lookup)
- Order/Draft order creation (success/failure)
- Validation errors
- Shopify API responses
- Unhandled exceptions
Each log entry includes:
- Timestamp (ISO format)
- Log type (REQUEST, CUSTOMER, ORDER_SUCCESS, etc.)
- Message
- Associated data (as JSON)
The server exposes these endpoints:
GET /— health checkPOST /api/create-order— create a Shopify orderPOST /api/create-draft-order— create a Shopify draft order
For both POST endpoints, the API will:
- validate request fields (name, variant_id are required)
- optionally find or create a Shopify customer by email
- build order or draft order line item properties (name, phone, email, reference file)
- add tags:
custom-designandapi-order(ordraft-order) - set financial status to
pendingfor orders - send a request to Shopify using the configured store and access token
- log request and result details to
logs/app.logand console
- If an
emailis provided, the API searches for an existing customer - If found, the existing customer is attached to the order
- If not found, a new customer is created with tags:
api-customer - If no
emailis provided, the order is created without a customer
Send JSON data in the request body. The API expects the following fields:
name(string) — required, used for customer first name and line item propertiesemail(string) — optional, but used to search/create a customer. Must be valid email format.phone(string) — optional; if provided, must use international format like+919999999999or+1234567890. Phone is included in billing/shipping address for visibility in Shopify dashboard.variant_id(number or string convertible to number) — required, the Shopify product variant IDquantity(number) — optional, defaults to1when missing or invalidreference_file(string) — optional custom value stored in line item properties (e.g., design file name)
{
"name": "John Doe",
"email": "john.doe@example.com",
"phone": "+1234567890",
"variant_id": 1234567890,
"quantity": 2,
"reference_file": "design-xyz.pdf"
}namemust be a string and is required.variant_idmust be a valid number and is required.quantitymust be greater than0if provided; otherwise the API defaults to1.emailis validated for format if included. It must contain @ and a domain.phoneis optional, but must be in international format if provided (e.g.,+1234567890).reference_fileis stored in line item properties as a custom field.- When email is provided but invalid, the request fails validation.
- When email is valid but no customer exists, a new customer is created.
- All orders are tagged with
custom-designandapi-order(ordraft-orderfor draft orders). - Orders have
financial_statusset topending.
POST /api/create-order
Response on success (HTTP 200):
{
"success": true,
"message": "Order created successfully",
"customer_id": 123456789,
"order_id": 987654321,
"order_name": "#1001",
"order_number": 1001,
"created_at": "2026-05-13T00:00:00Z"
}Response on validation error (HTTP 400):
{
"success": false,
"message": "Valid name is required"
}POST /api/create-draft-order
Response on success (HTTP 200):
{
"success": true,
"message": "Draft order created successfully",
"customer_id": 123456789,
"draft_order_id": 987654321,
"invoice_url": "https://your-store.myshopify.com/123456789/draft_orders/987654321/invoice",
"order_name": "#1001",
"status": "open",
"created_at": "2026-05-13T00:00:00Z"
}200 OK— request successful, order/draft order created400 Bad Request— validation error (missing or invalid fields)429 Too Many Requests— rate limit exceeded (max 100 requests per 15 minutes)500 Internal Server Error— server or Shopify API error
"Valid name is required"— name field is missing or not a string"Valid variant ID is required"— variant_id is missing or not a number"Invalid email format"— email provided but doesn't match email pattern"Quantity must be greater than 0"— quantity is less than or equal to 0"Order creation failed"— Shopify API returned an error"Too many requests"— rate limit exceeded
- The code uses Shopify API version
2026-04 - Rate Limiting — The app blocks more than 100 requests per 15 minutes from the same IP
- Request Timeout — All Shopify API requests have a 15-second timeout to prevent hanging
- Customer Creation —
createCustomerlogic only runs whenemailis present in the request - Error Responses — Failed Shopify API calls include the
shopify_responsedata for debugging - Tags — All customers are tagged with
api-customer. Orders are tagged withcustom-designandapi-orderordraft-order - Billing/Shipping Address — Both include name and phone for visibility in Shopify dashboard
- Line Item Properties — Custom properties are stored for tracking (name, phone, email, reference file)
- Logs Directory — Automatically created if it doesn't exist; old logs are appended to
logs/app.log
Problem: "❌ Missing environment variables"
Solution: Ensure your .env file contains both SHOPIFY_STORE and SHOPIFY_ACCESS_TOKEN.
Problem: "Order creation failed" with shopify_response error
Solution: Check that:
- The
variant_idexists in your Shopify store - The
SHOPIFY_ACCESS_TOKENhas permission to create orders - The
SHOPIFY_STOREdomain is correct - Check the logs in
logs/app.logfor the full Shopify API error
Problem: "Too many requests" (HTTP 429)
Solution: Wait 15 minutes before making more requests from the same IP, or use a different IP address.
Problem: Phone doesn't appear in Shopify order
Solution: Ensure phone is in international format (e.g., +12125551234 or +919999999999).
Problem: New customer created instead of finding existing customer
Solution: This is expected if the email in the request doesn't exactly match an existing customer email in your Shopify store.
- Name:
Dhruv Akbari - Email:
dhruvakbari303@gmail.com
Replace the author name and email above with your actual details.