Vinaway API Documentation
Integrate your e-commerce store with Vinaway's fulfillment network. Automate order processing, track shipments, and manage products directly from your application.
Introduction
The Vinaway API is organized around REST. Our API has predictable resource-oriented URLs, accepts form-encoded request bodies, returns JSON-encoded responses, and uses standard HTTP response codes, authentication, and verbs.
Production: https://api.vinaway.io/api
Development: https://dev.api.vinaway.io/api
Authentication
Authenticate your API requests using a Bearer token. To obtain a token, you need to exchange your email and password.
/token
Request Body
{
"email": "your_email@example.com",
"password": "your_password"
}
Response
{
"access_token": "76|5lrXZKyBRTRL8pDvpUBNZ...",
"token_type": "Bearer",
"expires_in": 18000
}
Create Order
Create a new production order. This endpoint accepts a list of items to be fulfilled.
/orders
Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| type | integer | Yes | Order type (1: Production) |
| external_order_id | string | No | Your unique identifier for this order. Max 255 characters, and must be unique per seller among orders that are not cancelled |
| production_line_id | integer | Yes | ID of the production line (e.g., 1 for Standard). The production line must support shipping to the order's country |
| note_seller | string | No | Free-text note for the production team. Max 1000 characters |
| shipping_label | string | No | URL of an existing shipping label. When provided, the customer and address fields below are not required, and the customer information is read from the label instead |
| customer_name | string | Conditional | Name of the customer. Required when shipping_label is not provided. Max 255 characters |
| string | No | Customer email address | |
| tel | string | No | Customer phone number |
| address1 | string | Conditional | Street address. Required when shipping_label is not provided. Max 255 characters |
| address2 | string | No | Additional address line (apartment, suite, unit…). Max 255 characters |
| city | string | Conditional | City. Required when shipping_label is not provided. Max 255 characters |
| state | string | Conditional | State code (e.g. NY) or state name. Resolved against the given country. Required when the country is US and shipping_label is not provided |
| zip | string | Conditional | ZIP / postal code, max 10 characters. Required when shipping_label is not provided |
| country | string | Yes | Country code (e.g. US). Looked up to resolve the country_id; an unknown or missing code fails with "Country not found" |
| vat_ioss | string | No | Customer VAT / tax number |
| items | array | Yes | Array of items to produce. At least one item is required |
Item Fields
Each entry of the "items" array describes one product to produce.
| Field | Type | Required | Description |
|---|---|---|---|
| items[].product_id | integer | Yes | ID of the product to produce. Must exist in the catalog |
| items[].product_sku_id | integer | No | ID of the product SKU (variant: size, colour…). Must be an existing, non-deleted SKU of the product |
| items[].quantity | integer | Yes | Quantity to produce. Between 1 and 1000 |
| items[].mockup1 | string | No | URL of the first mockup image of the item |
| items[].mockup2 | string | No | URL of the second mockup image of the item |
| items[].productSurfaces | array | No | Design files applied to each print surface of the item. See "Product Surface Fields" below |
Product Surface Fields
Each item in the "items" array may contain a "productSurfaces" array. Each product surface describes the design files applied to one print surface of the product.
| Field | Type | Required | Description |
|---|---|---|---|
| product_surface_id | integer | Yes | ID of the product surface the design is applied to |
| design_png | string | No | URL of the 2D design image (PNG). When provided, the image dimensions must exactly match the width and height configured for the product surface (e.g. 4500x5400 px) |
| design_emb | string | No | URL of the machine embroidery file (EMB format) |
| design_dst | string | No | URL of the machine embroidery file (DST format, Tajima) |
| screenshot | string | No | URL of a screenshot/preview image of the design, e.g. a preview of the mockup or embroidery layout |
| google_drive_folder_url | string | No | URL of a publicly accessible Google Drive folder containing the design files (design_png / design_dst / design_emb). Use this instead of uploading each file URL when your designs are stored in Drive |
Design requirements
- Each item must include at least one of: mockup1, mockup2, a Google Drive folder URL, or design files (design_png / design_dst / design_emb) on at least one product surface.
- If no mockup is provided, the Google Drive folder (when used) must be publicly accessible and contain design files.
- When design_png is validated against the product surface dimensions, the image is downloaded and checked; make sure the URL is publicly reachable.
Example Request
{
"type": 1,
"external_order_id": "ORD-2024-001",
"production_line_id": 1,
"note_seller": "Gift order, please pack carefully.",
"customer_name": "John Doe",
"address1": "123 Main St",
"city": "New York",
"zip": "10001",
"country": "US",
"state": "NY",
"items": [
{
"product_id": 1,
"product_sku_id": 1,
"quantity": 1,
"mockup1": "https://example.com/mockup-front.png",
"productSurfaces": [
{
"product_surface_id": 3,
"design_png": "https://example.com/design.png",
"design_emb": "https://example.com/design.emb",
"design_dst": "https://example.com/design.dst",
"screenshot": "https://example.com/design-preview.png"
}
]
}
]
}
Alternatively, when your design files are stored in Google Drive, you can send the folder URL instead of individual file URLs. The folder must be publicly accessible and contain the design files (design_png / design_dst / design_emb).
{
"type": 1,
"production_line_id": 1,
"customer_name": "John Doe",
"items": [
{
"product_id": 1,
"product_sku_id": 1,
"quantity": 1,
"productSurfaces": [
{
"product_surface_id": 3,
"google_drive_folder_url": "https://drive.google.com/drive/folders/1AbC123Xyz"
}
]
}
]
}
Success Response
The created order is returned — the same order object as the Get Order endpoint — with "success" and "message" added.
{
"internal_order_id": "VN7PIEA4FA5U",
"external_order_id": "ORD-2024-001",
"type": 1,
"status": 0,
"amount_subtotal": 2470,
"amount_shipping": 0,
"amount_total": 2470,
"customer_name": "John Doe",
"address1": "123 Main St",
"address2": null,
"city": "New York",
"state": "NY",
"zip": "10001",
"country": "US",
"customer_email": "john.doe@example.com",
"customer_tel": "+1 555 0100",
"note_seller": null,
"is_paid": 0,
"line_items": [
{
"product": {
"name": "Unisex T-Shirt"
},
"quantity": 1
}
],
"shipment_order": null,
"success": true,
"message": "Seller Order Created Successfully."
}
Get Order
Retrieve details of a specific order by its internal ID.
/orders/{internal_order_id}
Example Request
GET https://api.vinaway.io/api/orders/VN7PIEA4FA5U
Response
{
"internal_order_id": "VN7PIEA4FA5U",
"status": 0,
"amount_total": 2470,
"customer_name": "John Doe",
"line_items": [
{
"product": {
"name": "Unisex T-Shirt"
},
"quantity": 1
}
]
}
List Orders
Retrieve a paginated list of your orders.
/orders
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| page | integer | Page number (default: 1) |
| limit | integer | Number of items per page (default: 15) |
Production Lines
Get a list of available production lines to use when creating an order.
/production-lines
Response
{
"total": 2,
"data": [
{
"id": 1,
"name": "Standard",
"description": "Inproduction: 1-3 days\nShip : 3-7days",
"level": 1
},
{
"id": 2,
"name": "Express",
"description": "Inproduction 4h\nShip 1-3 days",
"level": 2
}
]
}
Products
Get a list of all products.
/products
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| page | integer | Page number (default: 1) |
| limit | integer | Number of items per page (default: 100) |
Response
{
"total": 50,
"data": [
{
"id": 1,
"name": "Classic T-Shirt",
"sku": "TSHIRT-001"
}
]
}
Variants
Get a list of all product variants (SKUs). Use these IDs when creating orders.
/product-skus
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| page | integer | Page number (default: 1) |
| limit | integer | Number of items per page (default: 100) |
Response
{
"total": 120,
"data": [
{
"id": 101,
"sku": "TSHIRT-BLK-S",
"product_name": "Classic T-Shirt",
"color": "Black",
"size": "S"
}
]
}
Webhooks
Vinaway can send HTTP POST notifications to a URL you configure when certain events happen in your account. This allows your application to react in real-time without polling our API.
| Event | Description |
|---|---|
| order_processed | Sent when an order finishes production and moves to "Waiting for Packaging" status. |
| order_status_updated | Sent whenever an order's status changes. The payload includes both the previous and current status codes. |
| shipment_order_created | Sent when a shipment order is created for an order. The payload includes the updated order with shipment details. |
Configuration
Configure your webhook URL and secret via the API, or contact your Vinaway account manager. Once configured, Vinaway will begin sending POST requests to that URL for the events described below.
/sellers/webhook-config
Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| webhook_url | string (URL) | No | The URL Vinaway will send webhook requests to. Set to null to disable. |
| webhook_secret | string | No | Shared secret used to sign webhook payloads via HMAC-SHA256. |
Example Request
PATCH /sellers/webhook-config
Authorization: Bearer YOUR_TOKEN
{
"webhook_url": "https://your-shop.com/webhooks/vinaway",
"webhook_secret": "your_shared_secret_12345"
}
Response
{
"success": true,
"message": "Webhook configuration updated successfully",
"data": {
"id": 42,
"name": "Example Store",
"webhook_url": "https://your-shop.com/webhooks/vinaway",
"webhook_secret": "your_shared_secret_12345"
}
}
Request Format
Method: POST
Content-Type: application/json
All webhook payloads follow this structure:
{
"event": "order_processed",
"data": { ... }
}
Verifying Signatures
Each webhook request includes an X-Webhook-Signature header containing an HMAC-SHA256 hex digest of the request body. Verify it to ensure the webhook came from Vinaway:
$secret = "your_shared_secret"; // Provided by Vinaway for your account
$body = file_get_contents('php://input');
$expected = hash_hmac('sha256', $body, $secret);
$received = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
if (!hash_equals($expected, $received)) {
http_response_code(401);
exit;
}
Retry Policy
Vinaway expects a 2XX response within 10 seconds. If your endpoint returns a non-2XX status or times out, the webhook is NOT automatically retried. Please ensure your endpoint is reliable.
Webhook: Order Processed
Sent when an order finishes production and moves to "Waiting for Packaging" status. The payload contains the full order detail, identical to the GET /orders/{id} response.
Payload
{
"event": "order_processed",
"data": {
"id": 313,
"internal_order_id": "VN7PIEA4FA5U",
"external_order_id": "ORD-2024-001",
"type": 1,
"status": 6,
"is_paid": 1,
"amount_subtotal": 2000,
"amount_shipping": 470,
"amount_total": 2470,
"customer_name": "John Doe",
"address1": "123 Main St",
"city": "New York",
"state_name": "NY",
"country_name": "United States",
"zip": "10001",
"tracking_number": null,
"tracking_carrier": null,
"seller": {
"id": 42,
"name": "Example Store"
},
"seller_order_skus": [
{
"id": 501,
"quantity": 1,
"price": 2000,
"product": {
"id": 1,
"name": "Unisex T-Shirt"
},
"seller_order_sku_designs": [...]
}
],
"production_line": {
"id": 1,
"name": "Standard"
},
"created_at": "2026-08-01 14:30:00"
}
}
Order Status Reference
| Status Code | Name | Description |
|---|---|---|
| -1 | Shipping Cost Processing | Order placed, calculating shipping |
| 0 | Pending | Awaiting processing |
| 1 | Ordering Design | Design being ordered |
| 2 | Waiting for Design Confirmation | Design awaiting seller confirmation |
| 3 | Waiting for Production | Design confirmed, queued for production |
| 4 | Approved for Production | Approved by factory |
| 5 | In Production | Currently being manufactured |
| 6 | Waiting for Packaging | Webhook trigger — production complete |
| 7 | Shipped | Package handed to carrier |
| 8 | Completed | Delivered / fulfillment complete |
| 9 | Refunded | Order refunded |
| 99 | Canceled | Order canceled |
Webhook: Order Status Updated
Sent whenever an order transitions from one status to another. The payload contains the full order detail, plus the previous and current status codes so you can track exactly what changed.
Payload
{
"event": "order_status_updated",
"data": {
"id": 313,
"internal_order_id": "VN7PIEA4FA5U",
"external_order_id": "ORD-2024-001",
"status": 7,
"previous_status": 6,
"current_status": 7,
"amount_total": 2470,
"customer_name": "John Doe",
"tracking_number": "TN123456789",
"tracking_carrier": "DHL",
"seller": {
"id": 42,
"name": "Example Store"
},
"seller_order_skus": [...],
"shipment_order": { ... },
"created_at": "2026-08-01 14:30:00"
}
}
Special Fields
| Field | Type | Description |
|---|---|---|
| previous_status | integer | The order status before the change. |
| current_status | integer | The new order status after the change. |
| status | integer | The current order status (same as current_status). |
Webhook: Shipment Order Created
Sent when a shipment order is created for an order. The payload contains the full order detail, including the newly created shipment order information.
Payload
{
"event": "shipment_order_created",
"data": {
"id": 313,
"internal_order_id": "VN7PIEA4FA5U",
"external_order_id": "ORD-2024-001",
"status": 7,
"amount_total": 2470,
"customer_name": "John Doe",
"tracking_number": "TN123456789",
"tracking_carrier": "DHL",
"seller": {
"id": 42,
"name": "Example Store"
},
"seller_order_skus": [...],
"shipment_order": {
"id": 101,
"shipment_order_code": "SO-2026-001",
"tracking_number": "TN123456789",
"tracking_carrier": "DHL",
"total_weight": 0.5,
"fee": 15000,
"status": "pending"
},
"created_at": "2026-08-01 14:30:00"
}
}