Artist Orders API
The Artist Orders API allows artists to view and fulfill orders from the gallery. Artists can see orders containing their products, mark items as shipped, and provide tracking information.
Authentication
All artist endpoints require Supabase authentication:
Authorization: Bearer <access_token>
Additionally, Row Level Security (RLS) policies ensure artists only see their own orders.
Endpoints
List Artist Orders
Retrieves all gallery orders containing the artist's products.
Endpoint: GET /api/gallery/artist/orders
Authentication: Required (Supabase JWT)
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
org_id | string | Yes | Artist's organization UUID |
status | string | No | Filter by status (paid, processing, shipped, delivered) |
limit | number | No | Max results (default: 50, max: 100) |
offset | number | No | Pagination offset (default: 0) |
Response:
{
"orders": [
{
"id": "artist_order_001",
"parentOrder": {
"id": "order_abc123",
"publicId": "GAL-2024-ABC123",
"createdAt": "2024-01-15T10:30:00Z",
"paidAt": "2024-01-15T10:32:00Z"
},
"status": "paid",
"subtotal": 120.00,
"artistPayout": 105.60,
"items": [
{
"id": "item_001",
"productId": "prod_001",
"productName": "Abstract Painting #5",
"quantity": 2,
"price": 60.00,
"image": "https://...",
"product": {
"sku": "ABS-005",
"inventory": 10
}
}
],
"shippingAddress": {
"name": "John Doe",
"line1": "123 Main St",
"city": "New York",
"state": "NY",
"postal_code": "10001",
"country": "US"
},
"trackingNumber": null,
"trackingUrl": null,
"shippedAt": null
}
],
"pagination": {
"total": 15,
"limit": 50,
"offset": 0,
"hasMore": false
}
}
Response Fields:
| Field | Type | Description |
|---|---|---|
orders | array | Array of artist order objects |
orders[].id | string | Artist order UUID |
orders[].parentOrder | object | Parent gallery order info |
orders[].status | string | Order status |
orders[].subtotal | number | Total for this artist's items |
orders[].artistPayout | number | Amount artist receives (88% of subtotal) |
orders[].items | array | Line items to fulfill |
orders[].shippingAddress | object | Where to ship (can be per-artist address) |
orders[].trackingNumber | string | Tracking number (if shipped) |
orders[].trackingUrl | string | Carrier tracking URL (if shipped) |
orders[].shippedAt | string | ISO 8601 timestamp (if shipped) |
pagination | object | Pagination metadata |
Example Request:
curl https://gallery.artbase.studio/api/gallery/artist/orders?org_id=org_abc123 \
-H "Authorization: Bearer <token>"
Example with Filters:
curl "https://gallery.artbase.studio/api/gallery/artist/orders?org_id=org_abc123&status=paid&limit=20" \
-H "Authorization: Bearer <token>"
Error Responses:
| Status | Error | Description |
|---|---|---|
| 400 | Organization ID required | Missing org_id parameter |
| 401 | Unauthorized | Missing or invalid token |
| 403 | Forbidden | User not member of organization |
Mark Order as Shipped
Updates an artist order to shipped status with tracking information.
Endpoint: POST /api/gallery/artist/orders/{id}/ship
Authentication: Required (Supabase JWT)
URL Parameters:
| Parameter | Type | Description |
|---|---|---|
id | string | Artist order UUID |
Request Body:
{
"trackingNumber": "1Z999AA10123456784",
"carrier": "UPS"
}
Request Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
trackingNumber | string | Yes | Shipment tracking number |
carrier | string | No | Carrier name ("UPS", "USPS", "FedEx", or custom) |
Response:
{
"success": true,
"order": {
"id": "artist_order_001",
"status": "shipped",
"trackingNumber": "1Z999AA10123456784",
"trackingUrl": "https://www.ups.com/track?tracknum=1Z999AA10123456784",
"shippedAt": "2024-01-16T14:20:00Z"
},
"parentOrderStatus": "partially_shipped"
}
Response Fields:
| Field | Type | Description |
|---|---|---|
success | boolean | Always true on success |
order | object | Updated artist order |
order.status | string | Now "shipped" |
order.trackingNumber | string | Tracking number provided |
order.trackingUrl | string | Auto-generated tracking URL |
order.shippedAt | string | ISO 8601 timestamp |
parentOrderStatus | string | Updated parent order status |
Example Request:
curl -X POST https://gallery.artbase.studio/api/gallery/artist/orders/artist_order_001/ship \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"trackingNumber": "1Z999AA10123456784",
"carrier": "UPS"
}'
Error Responses:
| Status | Error | Description |
|---|---|---|
| 400 | Tracking number required | Missing trackingNumber |
| 401 | Unauthorized | Missing or invalid token |
| 403 | Forbidden | Artist doesn't own this order |
| 404 | Order not found | Invalid order ID |
| 400 | Order already shipped | Cannot ship twice |
Cascading Status Updates:
When an artist marks their order as shipped, the parent order status is recalculated:
// Parent status logic
const allArtistOrders = await getArtistOrdersForParent(parentOrderId);
const allShipped = allArtistOrders.every(ao =>
ao.status === 'shipped' || ao.status === 'delivered'
);
const anyShipped = allArtistOrders.some(ao =>
ao.status === 'shipped' || ao.status === 'delivered'
);
let newParentStatus;
if (allShipped) {
newParentStatus = 'shipped'; // All artists have shipped
} else if (anyShipped) {
newParentStatus = 'partially_shipped'; // Some artists shipped
} else {
newParentStatus = 'paid'; // None shipped yet
}
Tracking URL Generation:
The system auto-generates tracking URLs based on carrier:
| Carrier | URL Template |
|---|---|
| UPS | https://www.ups.com/track?tracknum={number} |
| USPS | https://tools.usps.com/go/TrackConfirmAction?tLabels={number} |
| FedEx | https://www.fedex.com/fedextrack/?trknbr={number} |
| Custom | Stored as provided (artist provides full URL) |
Order Fulfillment Workflow
1. Receive Order Notification
When a customer completes checkout:
- Artist receives email notification (
sendArtistOrderNotificationEmail) - Email contains order details and items to ship
- Artist logs into dashboard to view order
2. View Order Details
Artist calls GET /api/gallery/artist/orders?org_id={org_id}:
const response = await fetch(
`/api/gallery/artist/orders?org_id=${orgId}&status=paid`,
{
headers: {
Authorization: `Bearer ${token}`,
},
}
);
const { orders } = await response.json();
3. Prepare Items
Artist:
- Locates items in inventory (using SKU if available)
- Packs items securely
- Prepares shipping label
4. Ship and Update Status
Artist calls POST /api/gallery/artist/orders/{id}/ship:
await fetch(`/api/gallery/artist/orders/${orderId}/ship`, {
method: 'POST',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
trackingNumber: '1Z999AA10123456784',
carrier: 'UPS',
}),
});
5. Customer Notification
System automatically:
- Updates parent order status
- Sends shipping notification email to customer (
sendShippingNotificationEmail) - Displays tracking info on customer tracking page
6. Receive Payout
Artist receives payout automatically:
- Timing: 2-7 business days after shipment (Stripe Standard payout)
- Amount: 88% of subtotal
- Destination: Artist's Stripe Connect account
- Visibility: View in Stripe Dashboard
Inventory Management
Artists should track inventory to avoid overselling:
Recommended Pattern
// When order received
async function handleNewOrder(order) {
for (const item of order.items) {
// Check inventory
const product = await getProduct(item.productId);
if (product.inventory < item.quantity) {
// Alert: insufficient inventory
await notifyArtist({
type: 'low_inventory',
product: product.name,
needed: item.quantity,
available: product.inventory,
});
}
// Reserve inventory
await updateProduct(item.productId, {
inventory: product.inventory - item.quantity,
});
}
}
// When order shipped
async function handleShipped(order) {
// Inventory already reserved, no action needed
console.log('Order shipped successfully');
}
Out of Stock Handling
If artist cannot fulfill:
- Contact customer - Use email from order
- Offer alternatives - Suggest similar products or refund
- Process refund - Contact gallery support for refund (manual process currently)
Shipping Best Practices
Recommended Carriers
| Carrier | Best For | Tracking Quality |
|---|---|---|
| UPS | High-value items, insurance | Excellent |
| USPS | Lightweight, domestic | Good |
| FedEx | Fast delivery, commercial | Excellent |
Packaging Guidelines
- Protect artwork: Use bubble wrap, cardboard corners
- Weatherproof: Seal in plastic before boxing
- Label clearly: Include return address
- Insure valuable items: Purchase carrier insurance for items >$100
Shipping Timeline
Aim to ship within 1-3 business days of receiving order:
- ⏱️ Same day: Exceptional service, happy customers
- ✅ 1-2 days: Standard timeframe, good experience
- ⚠️ 3-5 days: Acceptable but slow
- ❌ >7 days: Too slow, contact customer to explain delay
Analytics Integration
Artists can track performance using the Analytics API:
const analytics = await fetch(
`/api/gallery/artist/analytics?org_id=${orgId}`,
{
headers: { Authorization: `Bearer ${token}` },
}
);
const data = await analytics.json();
console.log(`Total orders: ${data.totalOrders}`);
console.log(`Total revenue: $${data.totalRevenue}`);
console.log(`Artist payout: $${data.artistPayout}`);
See Artist Analytics API for details.
Testing
Test Flow
- Create test order: Use Stripe test card to create order
- View orders: Call
GET /api/gallery/artist/ordersto see new order - Mark shipped: Call
POST .../shipwith test tracking number - Verify status: Check parent order updated to
partially_shippedorshipped
Test Data
Use these test tracking numbers:
{
"UPS": "1Z999AA10123456784",
"USPS": "9400111899562537883321",
"FedEx": "771234567890"
}