Appearance
Order History
API Type
eCommerce API - Uses API key in request body. See Authentication.
Retrieve order history for a user with pagination support.
Get Order History
Fetch a user's past orders with detailed information about products, pricing, and status.
Endpoint
POST https://{ecomm}.photobook.ai/api/v2/user/get-order-history.phpReplace {ecomm} with your assigned client identifier.
Example: https://yourclient.photobook.ai/api/v2/user/get-order-history.php
Authentication
See Authentication - eCommerce
Request Parameters
json
{
"env": "dev",
"key": "your-api-key",
"marketId": 0,
"language": "en",
"email": "user@example.com",
"cursor": "optional-pagination-token"
}| Parameter | Type | Required | Description |
|---|---|---|---|
env | string | Yes | Target environment: dev or prod |
key | string | Yes | Your programmatic access key |
marketId | integer | No | Target market ID. Defaults to 0 |
language | string | No | First 2 characters of language code (e.g., en). Defaults to en |
email | string | Yes | User's email address (plaintext, not encrypted) |
cursor | string | No | Pagination token from previous response. Fetches next page of results |
Response
json
{
"results": [
{
"orderId": "ORD-2024-001",
"displayDate": "15-04-2024 14:30",
"date": "2024-04-15 14:30:00",
"timestamp": 1713190200,
"email": "user@example.com",
"sourceOrderId": "INV-2024-12345",
"orders": [
{
"title": "Family Vacation 2024",
"coverPreview": "https://cdn.example.com/preview.jpg",
"quantity": 2,
"total": 59.98,
"product": {
"name": "Premium Photo Book",
"basePrice": 29.99,
"extraCostPerPage": 0.50
},
"displayStatus": "Processing"
}
],
"orderStatus": "Payment Complete",
"shippingAddress": {
"firstname": "John",
"lastname": "Doe",
"address_1": "123 Main Street",
"city": "New York",
"postcode": "10001",
"country": "United States"
},
"shippingCost": 5.99,
"voucher": "SAVE10",
"voucherAmount": 6.00,
"subTotal": 59.98,
"grandTotal": 59.97
}
],
"cursor": "next-page-token"
}Response Fields
Top-Level Fields
| Field | Type | Description |
|---|---|---|
results | array | Array of order objects (max 10 per request) |
cursor | string | Token for fetching next page. Undefined if no more results |
Order Object
| Field | Type | Description |
|---|---|---|
displayDate | string | Formatted date for display (DD-MM-YYYY HH:mm) |
timestamp | integer | Unix timestamp in seconds (recommended for timezone conversion) |
sourceOrderId | string | Invoice/reference order ID for display |
orders | array | Line items in the order |
orderStatus | string | Payment status |
shippingAddress | object | Delivery address |
shippingCost | float | Shipping charges |
voucher | string | Coupon/voucher code used (if any) |
voucherAmount | float | Discount amount from voucher |
subTotal | float | Subtotal before shipping and discounts |
grandTotal | float | Final total amount paid |
Line Item (orders array)
| Field | Type | Description |
|---|---|---|
title | string | Photobook title |
coverPreview | string | URL to cover thumbnail image |
quantity | integer | Number of copies ordered |
total | float | Total cost for this line item |
product.name | string | Product name |
product.basePrice | float | Base price of product |
product.extraCostPerPage | float | Cost per additional page |
displayStatus | string | Order fulfillment status (e.g., "Processing", "Shipped") |
Shipping Address
| Field | Type | Description |
|---|---|---|
firstname | string | First name |
lastname | string | Last name |
address_1 | string | Address line 1 |
address_2 | string | Address line 2 (optional) |
city | string | City |
postcode | string | Postal/ZIP code |
state | string | State/province |
country | string | Country name |
Pagination
The API returns a maximum of 10 orders per request. Use the cursor field to fetch additional pages.
How Pagination Works
- Make initial request without
cursor - Display the 10 results
- If response includes a
cursor, there are more results - Make next request with the
cursorvalue - Repeat until
cursoris undefined
⚠️ Important
resultsmay be empty even ifcursoris returned- Always check for
cursorto determine if more pages exist - Continue fetching as long as
cursoris present
Pagination Strategies
Lazy Loading (Recommended):
javascript
// Load initial page
const firstPage = await getOrderHistory(email);
displayOrders(firstPage.results);
// Load more when user scrolls to bottom
if (firstPage.cursor) {
window.addEventListener('scroll', () => {
if (isScrolledToBottom() && !loading) {
loadMoreOrders(firstPage.cursor);
}
});
}Load All Pages:
javascript
async function getAllOrders(email) {
let allOrders = [];
let cursor = null;
do {
const page = await getOrderHistory(email, cursor);
allOrders = allOrders.concat(page.results);
cursor = page.cursor;
} while (cursor);
return allOrders;
}Example Implementation
javascript
async function getOrderHistory(email, cursor = null) {
const requestData = {
env: 'dev',
key: 'your-api-key',
marketId: 0,
language: 'en',
email: email
};
// Add cursor if provided
if (cursor) {
requestData.cursor = cursor;
}
const response = await fetch('https://{ecomm}.photobook.ai/api/v2/user/get-order-history.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(requestData)
});
return await response.json();
}
// Display orders in UI
async function displayUserOrders(email) {
const { results, cursor } = await getOrderHistory(email);
results.forEach(order => {
console.log(`Order ${order.sourceOrderId}`);
console.log(`Date: ${order.displayDate}`);
console.log(`Total: ${order.grandTotal}`);
console.log(`Status: ${order.orderStatus}`);
order.orders.forEach(item => {
console.log(` - ${item.title} (${item.quantity}x) - ${item.displayStatus}`);
});
});
// Check if more pages exist
if (cursor) {
console.log('More orders available. Call with cursor:', cursor);
}
}Timezone Considerations
The displayDate field uses server timezone. For better user experience:
- Use the
timestampfield (Unix timestamp in seconds) - Convert to user's local timezone
- Format according to user's locale
javascript
function formatOrderDate(timestamp) {
const date = new Date(timestamp * 1000); // Convert to milliseconds
return date.toLocaleDateString(navigator.language, {
year: 'numeric',
month: 'long',
day: 'numeric',
hour: '2-digit',
minute: '2-digit'
});
}Suggested Practices
- Implement Lazy Loading: Don't load all pages at once; load as needed
- Show Loading States: Display indicators during pagination
- Handle Empty Results: Check if
resultsarray is empty before rendering - Display Status Clearly: Use
displayStatusfor displaying the order's current status - Link to Details: Consider linking to a detailed order view for each order