Print-on-Demand Production System API - Version 2
The PTG API is a RESTful API for managing print-on-demand orders. It provides endpoints for creating orders, checking order status, and administrative functions.
Base URL: https://api.picthegift.com
All API requests should use HTTPS. The API returns JSON responses.
Version 2 of the PTG API introduces several breaking changes from Version 1 (Legacy). If you are migrating from Version 1, please review the following changes:
Version 2 uses JWT (JSON Web Token) authentication via the Authorization: Bearer header. This replaces the OAuth 2 Basic authentication method used in Version 1.
JWT tokens are obtained from the Pic The Gift customer portal. See the Authentication section for details.
Several field names have changed in Version 2:
order_nbr → customer_order_id (order identifier)ptg_part_number → ptg_item_code (item code)item_qty → qty (item quantity)gift_message field has been removed (no longer supported)Version 1 (Legacy) endpoints continue to support the old field names for backward compatibility.
Version 2 requires application/json for all request bodies. The application/x-www-form-urlencoded content type is no longer supported.
application/json and application/x-www-form-urlencodedapplication/json onlyMost API endpoints require JWT (JSON Web Token) authentication. Authentication tokens are available in the Pic The Gift customer portal, which is a separate application.
Include your JWT token in the Authorization header of your requests:
Authorization: Bearer YOUR_JWT_TOKEN_HERE
Create a new order. This endpoint validates the order data, checks item availability, validates artwork URLs, and creates the order.
The request body should be a JSON object. Below is a complete reference of all available fields:
| Field | Required | Description | Allowable Values |
|---|---|---|---|
customer_order_id |
Yes | Customer's unique order identifier | Any string, must be unique per customer |
shipto_name |
Yes | Recipient's full name | Any string |
shipto_address_1 |
Yes | Primary shipping address line | Any string |
shipto_address_2 |
No | Secondary shipping address line (apartment, suite, etc.) | Any string |
shipto_city |
Yes | Shipping city | Any string |
shipto_state |
Yes | Shipping state or province | Any string |
shipto_zip |
Yes | Shipping ZIP or postal code | Any string |
shipto_country |
Yes | Shipping country code | 2 letter ISO country code (e.g., "US", "CA") |
shipto_phone |
No | Recipient's phone number | Any string |
ship_method |
Yes | Shipping method | Any string (see Preferred Shipping Methods table below) |
custom_pack_slip |
Yes | Custom pack slip URL | Valid URL pointing to an image (JPG or PNG) or PDF that is 4x6 inches dimensions |
ship_acct_num |
No | 3rd party shipping account number | Any string |
tracking_callback |
No | URL to receive tracking number updates | Valid HTTPS URL |
external_customer_id |
No | Customer account identifier for your records | Any string |
handling |
No | Expedited production handling | "URG" or "RUSH" (surcharge applies) |
returnto_name |
No | Return address name | Any string |
returnto_address1 |
No | Return address line 1 | Any string |
returnto_address2 |
No | Return address line 2 | Any string |
returnto_city |
No | Return address city | Any string |
returnto_state |
No | Return address state | Any string |
returnto_country |
No | Return address country | 2 letter ISO country code |
returnto_postal_code |
No | Return address postal code | Any string |
returnto_company |
No | Return address company name | Any string |
returnto_phone |
No | Return address phone number | Any string |
items |
Yes | Array of order items (at least one required) | Array of item objects |
| Field | Required | Description | Allowable Values |
|---|---|---|---|
ptg_item_code |
Yes | Pic The Gift's item code | Valid product code from Pic The Gift's catalog |
customer_item_code |
No | Customer's item code for reference, can be returned with tracking number updates | Any string |
line_num |
No | Line number will be returned with tracking number updates | Any string |
qty |
Yes | Quantity of items | Integer greater than 0 |
artwork_url_1 through artwork_url_6 |
Conditional** | Artwork file to be printed on the item. artwork_url_1 is "front side", artwork_url_2 is "back side" typically. | Valid HTTPS URL returning image |
personalization_text_1 through personalization_text_15 |
No | Personalization text fields (1-15). These are very helpful for visual quality control and tracking. | Any string |
** artwork_url_1 to 6 is required depending on the product's requirement. example: double sided product requires both artwork_url_1 and artwork_url_2
| Rate Shop | GUI Name | Code |
|---|---|---|
| Y | 1 Day | 1_day |
| Y | 2 Day | 2_day |
| Y | 3 Day | 3_day |
| Y | Economy | economy |
| Y | International Economy | int_economy |
| Y | International Priority | int_priority |
| N | FedEx 2 Day | fedex_2_day |
| N | FedEx Ground | fedex_ground |
| N | FedEx International Economy | fedex_int_economy |
| N | FedEx Standard Overnight | fedex_std_overnight |
| N | UPS 2 Day | ups_2_day |
| N | UPS 3 Day | ups_3_day |
| N | UPS Ground | ups_ground |
| N | UPS Next Day | ups_next_day |
| N | USPS First Class | usps_first_class |
| N | USPS Ground Advantage | usps_ground_advantage |
| N | USPS Priority | usps_priority |
The API validates:
Response includes rate limit information:
X-RateLimit-Limit - Maximum requests per windowX-RateLimit-Remaining - Remaining requestsX-RateLimit-Reset - Unix timestamp when limit resets| Field | Required | Description | Allowable Values |
|---|---|---|---|
order_nbr |
Yes | Unique order identifier | Any string |
shipto_name |
Yes | Recipient's full name | Any string |
shipto_address_1 |
Yes | Primary shipping address line | Any string |
shipto_address_2 |
Yes | Secondary shipping address line (apartment, suite, etc.) | Any string |
shipto_city |
Yes | Shipping city | Any string |
shipto_state |
Yes | Shipping state or province | Any string |
shipto_zip |
Yes | Shipping ZIP or postal code | Any string |
shipto_country |
Yes | Shipping country code | ISO country code (e.g., "US", "CA") |
shipto_phone |
Yes | Recipient's phone number | Any string |
ship_method |
Yes | Shipping method | Any string (see Preferred Shipping Methods table below) |
tracking_callback |
Yes | URL to receive tracking number updates | Valid HTTPS URL |
items |
Yes | Array of order items (at least one required) | Array of item objects |
external_customer_id |
No | Customer account identifier for your records | Any string |
notes |
No | Order notes | Any string |
gift_message |
No | Gift message to include with order | Any string |
handling |
No | Expedited production handling | "URG" or "RUSH" (surcharge applies) |
returnto_name |
No | Return address name | Any string |
returnto_address1 |
No | Return address line 1 | Any string |
returnto_address2 |
No | Return address line 2 | Any string |
returnto_city |
No | Return address city | Any string |
returnto_state |
No | Return address state | Any string |
returnto_country |
No | Return address country | Any string |
returnto_postal_code |
No | Return address postal code | Any string |
returnto_company |
No | Return address company name | Any string |
returnto_phone |
No | Return address phone number | Any string |
| Field | Required | Description | Allowable Values |
|---|---|---|---|
ptg_part_number |
Yes | Product part number | Valid product code from catalog |
artwork_url_1 |
Yes | Artwork file for side 1 (front side of product) | Valid HTTPS URL returning image |
item_qty |
Yes | Quantity of items | Integer greater than 0 |
artwork_url_2 |
No | Artwork file for side 2 (back side of product) | Valid HTTPS URL returning image |
artwork_url_3 |
No | Artwork file for side 3 | Valid HTTPS URL returning image |
artwork_url_4 |
No | Artwork file for side 4 | Valid HTTPS URL returning image |
artwork_url_5 |
No | Artwork file for side 5 | Valid HTTPS URL returning image |
artwork_url_6 |
No | Artwork file for side 6 | Valid HTTPS URL returning image |
name |
No | Item name for reference only | Any string |
line_num |
No | Line number will be returned with tracking number updates | Any string |
item_name_packslip |
No | Item name for pack slip | Any string |
personalization_text_1 through personalization_text_15 |
No | Personalization text fields (1-15). These are very helpful for visual quality control and tracking. | Any string |
| Rate Shop | GUI Name | Code |
|---|---|---|
| Y | 1 Day | 1_day |
| Y | 2 Day | 2_day |
| Y | 3 Day | 3_day |
| Y | Economy | economy |
| Y | International Economy | int_economy |
| Y | International Priority | int_priority |
| N | FedEx 2 Day | fedex_2_day |
| N | FedEx Ground | fedex_ground |
| N | FedEx International Economy | fedex_int_economy |
| N | FedEx Standard Overnight | fedex_std_overnight |
| N | UPS 2 Day | ups_2_day |
| N | UPS 3 Day | ups_3_day |
| N | UPS Ground | ups_ground |
| N | UPS Next Day | ups_next_day |
| N | USPS First Class | usps_first_class |
| N | USPS Ground Advantage | usps_ground_advantage |
| N | USPS Priority | usps_priority |
The API validates:
Response includes rate limit information:
X-RateLimit-Limit - Maximum requests per windowX-RateLimit-Remaining - Remaining requestsX-RateLimit-Reset - Unix timestamp when limit resets{
"customer_order_id": "ORDER123",
"shipto_name": "John Doe",
"shipto_address_1": "123 Main St",
"shipto_city": "New York",
"shipto_state": "NY",
"shipto_zip": "10001",
"shipto_country": "US",
"ship_method": "2_day",
"custom_pack_slip": "https://example.com/packslip.pdf",
"items": [
{
"ptg_item_code": "TSHIRT-001",
"qty": 1,
"artwork_url_1": "https://example.com/artwork.jpg"
}
]
}
{
"status": "success",
"customer_order_id": "ORDER123",
"ptg_payload_id": 3894513,
"messages": ["Order ORDER123 was created successfully!"],
"payload_received": { ... }
}
{
"status": "error",
"customer_order_id": "ORDER123",
"ptg_payload_id": 3894513,
"messages": [
"<TSHIRT-001> is out of stock",
"<https://example.com/artwork.jpg> is not valid"
],
"payload_received": { ... }
}
Get tracking number for an order using the customer's order identifier.
Request Body:
{
"customer_order_id": "ORDER123"
}
Success Response:
{
"status": "ok",
"customer_order_id": "ORDER123",
"ptg_payload_id": 5145411,
"tracking_number": "61290983132311826002365",
"carrier": "fedex",
"carrier_service": "fedex_smartpost_parcel_select",
"ship_date": "2018-07-08"
}
Error Response:
{
"status": "failed",
"messages": ["Order not found."]
}
Note: Tracking number may be null if the order has not been shipped yet.
Request Body:
{
"order_nbr": "0FA667S-45"
}
Success Response:
{
"status": "ok",
"order_nbr": "0FA667S-45",
"order_id": "5145411",
"tracking_number": "61290983132311826002365",
"carrier": "fedex",
"carrier_service": "fedex_smartpost_parcel_select",
"ship_date": "2018-07-08"
}
Error Response:
{
"status": "failed",
"messages": ["Order not found."]
}
Note: Tracking number may be null if the order has not been shipped yet.
Modify an existing order. At least one optional parameter must be provided.
Request Body:
{
"customer_order_id": "ORDER123",
"shipto_name": "Jane Doe",
"shipto_address_1": "456 Oak Ave",
"shipto_address_2": "Apt 4B",
"shipto_city": "Los Angeles",
"shipto_state": "CA",
"shipto_zip": "90001",
"shipto_country": "US",
"shipto_phone": "555-5678",
"ship_method": "express"
}
Required: customer_order_id - the customer's order identifier
Optional Parameters: shipto_name, shipto_address_1, shipto_address_2, shipto_city, shipto_state, shipto_zip, shipto_country, shipto_phone, ship_method
Success Response:
{
"status": "success",
"message": "Successfully modified!"
}
Error Response:
{
"status": "failed",
"messages": "Can't find order id."
}
{
"status": "failed",
"messages": "No Changes Made!"
}
{
"status": "failed",
"messages": "Order Number {YourOrderNbr} is Cancelled or Closed, all fields and lines for this document will be skipped"
}
Request Body:
{
"order_nbr": "0FA667S-45",
"shipto_name": "Jane Doe",
"shipto_address_1": "456 Oak Ave",
"shipto_address_2": "Apt 4B",
"shipto_city": "Los Angeles",
"shipto_state": "CA",
"shipto_zip": "90001",
"shipto_country": "US",
"shipto_phone": "555-5678",
"ship_method": "express",
"gift_message": "Happy Birthday!"
}
Required: order_nbr - the customer's order identifier
Optional Parameters: shipto_name, shipto_address_1, shipto_address_2, shipto_city, shipto_state, shipto_zip, shipto_country, shipto_phone, ship_method, gift_message
Success Response:
{
"status": "success",
"message": "Successfully modified!"
}
Error Response:
{
"status": "failed",
"messages": "Can't find order id."
}
{
"status": "failed",
"messages": "No Changes Made!"
}
{
"status": "failed",
"messages": "Order Number {YourOrderNbr} is Cancelled or Closed, all fields and lines for this document will be skipped"
}
Cancel an existing order. Cancellation is only allowed until the order is in the production queue.
Request Body:
{
"customer_order_id": "ORDER123"
}
Required: customer_order_id - the customer's order identifier
Success Response:
{
"status": "success",
"message": "Successfully Cancelled! It may take up to 5 minutes to complete."
}
Error Response:
{
"status": "failed",
"messages": "Can't find order id."
}
{
"status": "failed",
"messages": "Order Number {YourOrderNbr} is Cancelled or Closed, all fields and lines for this document will be skipped"
}
Request Body:
{
"order_nbr": "0FA667S-45"
}
Required: order_nbr - the customer's order identifier
Success Response:
{
"status": "success",
"message": "Successfully Cancelled! It may take up to 5 minutes to complete."
}
Error Response:
{
"status": "failed",
"messages": "Can't find order id."
}
{
"status": "failed",
"messages": "Order Number {YourOrderNbr} is Cancelled or Closed, all fields and lines for this document will be skipped"
}
Get a list of all available products with their item codes and status.
Success Response:
[
{
"ptg_item_code": "TB1416S-RD",
"product_status": "in_stock",
"required_artwork_urls": 1
},
{
"ptg_item_code": "TB1416S-BL",
"product_status": "in_stock",
"required_artwork_urls": 1
},
{
"ptg_item_code": "TB1416S-PK",
"product_status": "in_stock",
"required_artwork_urls": 1
}
]
Response Fields:
ptg_item_code - Product item codeproduct_status - Product stock status: "in_stock", "discontinued", "low", or "out_of_stock"required_artwork_urls - Number of artwork URLs required for this product (0-6)Get a single product by its item code.
URL Parameters:
item_code - The product item code (e.g., "TB1416S-RD")Success Response:
{
"ptg_item_code": "TB1416S-RD",
"product_status": "in_stock",
"required_artwork_urls": 1
}
Error Response:
{
"status": "error",
"message": "Product not found"
}
Response Fields:
ptg_item_code - Product item codeproduct_status - Product stock status: "in_stock", "discontinued", "low", or "out_of_stock"required_artwork_urls - Number of artwork URLs required for this product (0-6)The API implements rate limiting to prevent abuse and ensure fair usage.
When rate limit is exceeded, the API returns:
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1704567890
{
"status": "error",
"message": "Rate limit exceeded. Please try again later."
}
| Code | Meaning | Description |
|---|---|---|
| 200 | OK | Request successful |
| 201 | Created | Order created successfully |
| 400 | Bad Request | Validation errors in request |
| 401 | Unauthorized | Invalid or missing JWT token |
| 403 | Forbidden | Access denied |
| 429 | Too Many Requests | Rate limit exceeded |
| 500 | Internal Server Error | Server error |
| 503 | Service Unavailable | Service temporarily unavailable |