Order Handoff API
Social Print Studio provides an API endpoint that lets external applications add products to our Shopify cart. Your app sends a simple JSON payload describing what to add, and receives a URL to redirect the customer to. The customer lands on our Shopify cart with the product already added, and can then checkout and pay directly on our website. We handle production, printing, and any customer service.
What you don’t need
- Shopify API credentials or access tokens
- Knowledge of Shopify variant IDs
- Access to our database
- Any understanding of our internal systems
What you do need
- The variant SKU for the product (must exactly match a SKU in our Shopify store — see SKU Requirements)
- A source identifier for your app (you create this yourself, based on your app name)
- Project data with at least one publicly accessible photo URL
- The ability to make an HTTP POST request and redirect the user’s browser
- (Optional) An API key in the
Authorizationheader for order attribution, revenue split, and tracking
Endpoint
Content-Type: application/json
Authorization: Bearer <your-api-key> (optional)Request Body
Required Fields
| Field | Type | Description |
|---|---|---|
sku | string | The Shopify product SKU. Must exactly match a variant SKU in our Shopify store. |
source | string | An identifier for your application (e.g. "my-app-name"). Used for tracking and debugging. |
projectData | object | Project/order data to persist for fulfillment. All products require this since they are custom printed. |
Optional Fields
| Field | Type | Default | Description |
|---|---|---|---|
email | string | — | A contact email address. Highly recommended — allows us to reach out to you if there are any issues with the order. |
quantity | number | 1 | How many copies to add to the cart. Must be a positive integer. |
properties | object | {} | Extra key-value pairs to attach to the Shopify line item. See Line Item Properties. |
checkout | boolean | false | Skip the cart and send the customer straight to checkout. See Direct Checkout. |
Project Data
The projectData object contains the custom content (photos, designs, etc.) that our fulfillment team needs to access when producing the order. When included, the data is saved to our project database and a unique projectId is generated. This ID is automatically attached to the Shopify line item.
| Field | Type | Description |
|---|---|---|
projectData.photos | string[] | Array of image URLs. Must be publicly accessible. At least one URL is required. |
projectData.metadata | object | Any arbitrary JSON-serializable data you want to persist with the project. Optional in most cases. |
Photo URL Requirements
| Requirement | Details |
|---|---|
| Formats | JPG or PNG recommended |
| Max file size | 50 MB per image |
| URL validity | Must remain publicly accessible for at least one week after the order is placed |
Line Item Properties
The properties object lets you attach key-value string pairs to the Shopify cart line item. These are visible in the Shopify order admin and available to our fulfillment systems.
_ (underscore) to hide them from the customer on the storefront. Properties without the underscore prefix will be visible to the customer in their cart and order confirmation.| Example Key | Description |
|---|---|
_project_Id | A project ID from your app (hidden from customer). Useful if you need to cross-reference an order later. |
_cover_preview_url | A URL shown as the product thumbnail/preview image in the cart (hidden from customer). |
Edit Project Link | A URL letting the customer return to your app to edit their project. Visible to the customer. |
Project Name | An optional customer-facing name, shown in the cart. Visible to the customer. |
Response
Success (200)
{
"success": true,
"redirectUrl": "https://socialprintstudio.com/pages/newcart?cartKey=prod_1707400000_abc123def",
"projectId": "65a1b2c3d4e5f6a7b8c9d0e1"
}| Field | Type | Description |
|---|---|---|
success | boolean | true if the item was staged successfully. |
redirectUrl | string | The URL to redirect the customer’s browser to. Single-use — works once, then expires. |
projectId | string | The database ID of the saved project. Store this for your own records if needed. |
After receiving the response, redirect the customer’s browser to redirectUrl.
Error Responses
| Status | Meaning |
|---|---|
400 | Missing or invalid required field (sku, source, or projectData). Check the error message. |
401 | Invalid API key. Only returned when an Authorization header is provided but the key is not valid. Omitting the header entirely is fine. |
405 | Wrong HTTP method. Use POST. |
502 | SKU could not be resolved to a Shopify product. It likely doesn’t match any variant in our store. |
500 | Internal server error. Contact us if this persists. |
All error responses include an error field with a human-readable message:
{
"error": "Missing required field: \"sku\" (string). This should be the Shopify product SKU."
}Direct Checkout
By default, the redirectUrl sends the customer to the Social Print Studio cart where they can review their order before checking out. If you’d rather skip the cart and send the customer straight to checkout, add "checkout": true to your request body. Everything else stays the same — same endpoint, same fields, same response format. The only difference is where the redirectUrl points.
When to use direct checkout
- Single-product apps where the cart feels like an unnecessary extra step. The customer already decided what they want in your app.
- AI agents creating a one-off print for a single user. Going straight to payment is the most natural flow.
- External-site handoffs where showing another storefront’s cart could be confusing or distracting. Direct checkout keeps the experience seamless.
checkout or set it to false, the behavior is exactly the same as before — the customer lands on the cart page. This is fully backward compatible.Direct Checkout Example
curl -X POST https://printkit.dev/api/add-to-cart \
-H "Content-Type: application/json" \
-d '{
"sku": "metal-print-4x4",
"source": "my-app",
"email": "[email protected]",
"checkout": true,
"projectData": {
"photos": ["https://cdn.example.com/photo.jpg"]
}
}'Examples
Minimal Example — Simple Photo Product
curl -X POST https://printkit.dev/api/add-to-cart \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"sku": "metal-print-4x4",
"source": "my-partner-app",
"email": "[email protected]",
"projectData": {
"photos": [
"https://cdn.example.com/uploads/user123/photo-sunset.jpg"
]
}
}'
# Response:
# { "success": true, "redirectUrl": "https://...", "projectId": "..." }
# Redirect the customer's browser to redirectUrlFull Example — Photo Product with Metadata
curl -X POST https://printkit.dev/api/add-to-cart \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"sku": "photo-books-softcover",
"quantity": 1,
"source": "my-partner-app",
"email": "[email protected]",
"projectData": {
"photos": [
"https://cdn.example.com/uploads/user123/cover-file.jpg",
"https://cdn.example.com/uploads/user123/page-1.jpg",
"https://cdn.example.com/uploads/user123/page-2.jpg",
"https://cdn.example.com/uploads/user123/page-3.jpg",
"https://cdn.example.com/uploads/user123/page-4.jpg",
"https://cdn.example.com/uploads/user123/page-5.jpg",
"https://cdn.example.com/uploads/user123/page-38.jpg"
],
"metadata": {
"bookTitle": "Summer Vacation 2025",
"customerNotes": "Extra info stored with the order record."
}
},
"properties": {
"Project Name": "Summer Vacation 2025",
"_cover_preview_url": "https://cdn.example.com/previews/user123/cover-thumb.jpg"
}
}'Multiple Quantity
curl -X POST https://printkit.dev/api/add-to-cart \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"sku": "photo-print-30x40",
"quantity": 3,
"source": "my-partner-app",
"projectData": {
"photos": ["https://cdn.example.com/photo1.jpg"]
}
}'SKU Requirements
The sku value must exactly match a product variant SKU in our Shopify store. If the SKU doesn’t match, the API returns a 502 error.
- SKUs are case-sensitive and typically lowercase with hyphens (e.g.
metal-print-8x10,photo-books-softcover) - Some products include style qualifiers (e.g.
photo-print-30x40-fullbleed,print-8x10-black-mat) - For the fastest machine-friendly lookup, filter
https://printkit.dev/variants.jsonand then verify the selected SKU against the per-product JSON file
Integration Flow
┌─────────────────────┐
│ Your Application │
│ │
│ 1. User finishes │
│ creating their │
│ product │
│ │
│ 2. POST to │
│ /api/add-to-cart│
│ with SKU + │
│ project data │
└────────┬────────────┘
│
▼
┌─────────────────────┐
│ Our API Endpoint │
│ │
│ 3. Saves project │
│ data to our DB │
│ │
│ 4. Stages cart │
│ items │
│ │
│ 5. Returns │
│ redirectUrl │
└────────┬────────────┘
│
▼
┌─────────────────────┐
│ Your app redirects │
│ the user's browser │
│ to redirectUrl │
└────────┬────────────┘
│
┌────┴─────┐
▼ ▼
┌────────┐ ┌────────────┐
│ Cart │ │ Checkout │
│(default│ │(checkout: │
│ flow) │ │ true) │
│ │ │ │
│Customer│ │ Customer │
│reviews │ │ goes │
│cart, │ │ straight │
│then │ │ to payment │
│checks │ │ │
│out │ │ │
└────────┘ └────────────┘Important Notes
- The redirect URL is single-use. Once the Shopify cart page retrieves the cart data, the key is deleted. Do not attempt to reuse it.
- Photo URLs must be publicly accessible. Our fulfillment system downloads these images when producing the order. URLs behind authentication or on localhost will not work. URLs must remain valid for at least one week. If you need simple image hosting, see the Image Upload API.
- The
sourcefield is important. It helps us track which app generated the order and debug issues. Pick a consistent, descriptive identifier and use it on every request. - CORS is enabled. You can call this endpoint from client-side JavaScript. If you call from a backend server, make sure you pass the redirect URL to the customer’s browser for the final redirect step.
- Request size limit is 10 MB. If you’re including many photo URLs or large metadata objects, keep the total payload under 10 MB.
- The
projectIdin the response is the database reference for the saved project. Store this in your own system if you may need to reference it later for debugging or support.