Bulk Operations
Create multiple orders in a single API call. The bulk endpoint processes orders concurrently, making it significantly faster than sequential individual requests.
When to Use Bulk Operations
- Batch imports: Migrating orders from another system
- Corporate provisioning: Granting access to multiple users at once
- Promotional campaigns: Mass distribution of promotional access
- Subscription renewals: Processing multiple renewals simultaneously
Creating Orders in Bulk
Endpoint
POST /api/v3/orders/bulk
Request Body
{
"orders": [
{
"type": "permission",
"external_id": "BULK-001",
"user": { "email": "[email protected]" },
"products": [{ "type": "content", "external_id": "EBOOK-001" }]
},
{
"type": "permission",
"external_id": "BULK-002",
"user": { "email": "[email protected]" },
"products": [{ "type": "content", "external_id": "EBOOK-001" }]
}
]
}
Request Structure
| Field | Type | Description |
|---|---|---|
orders | array | Array of order objects (1-100 orders) |
Each order object follows the same structure as individual order creation. See:
Limits
| Limit | Value |
|---|---|
| Maximum orders per request | 100 |
| Minimum orders per request | 1 |
Request Examples
Bulk Permission Orders
curl -X POST "https://yourstore.publica.la/api/v3/orders/bulk" \
-H "X-User-Token: your-api-token" \
-H "Content-Type: application/json" \
-d '{
"orders": [
{
"type": "permission",
"external_id": "PROMO-001",
"user": {
"id": "user-001",
"email": "[email protected]"
},
"products": [
{
"type": "content",
"external_id": "9781234567890"
}
]
},
{
"type": "permission",
"external_id": "PROMO-002",
"user": {
"id": "user-002",
"email": "[email protected]"
},
"products": [
{
"type": "content",
"external_id": "9781234567890"
}
]
},
{
"type": "permission",
"external_id": "PROMO-003",
"user": {
"id": "user-003",
"email": "[email protected]"
},
"products": [
{
"type": "content",
"external_id": "9781234567890"
}
]
}
]
}'
Bulk Orders with Different Types
curl -X POST "https://yourstore.publica.la/api/v3/orders/bulk" \
-H "X-User-Token: your-api-token" \
-H "Content-Type: application/json" \
-d '{
"orders": [
{
"type": "permission",
"external_id": "FREE-ACCESS-001",
"user": { "email": "[email protected]" },
"products": [
{ "type": "subscription", "external_id": "PREMIUM-PLAN" }
]
},
{
"type": "report",
"external_id": "PARTNER-SALE-001",
"return_url": "https://partner.com/receipt",
"unit_price": 29.99,
"currency_id": "USD",
"user": {
"id": "partner-customer-001",
"email": "[email protected]"
},
"products": [
{
"type": "content",
"external_id": "EBOOK-001",
"unit_price": 29.99,
"currency_id": "USD"
}
]
}
]
}'
Bulk Orders with Expiration
curl -X POST "https://yourstore.publica.la/api/v3/orders/bulk" \
-H "X-User-Token: your-api-token" \
-H "Content-Type: application/json" \
-d '{
"orders": [
{
"type": "permission",
"external_id": "TRIAL-001",
"user": { "email": "[email protected]" },
"products": [
{
"type": "subscription",
"external_id": "PREMIUM-MONTHLY",
"expiration_date": "2025-01-31"
}
]
},
{
"type": "permission",
"external_id": "TRIAL-002",
"user": { "email": "[email protected]" },
"products": [
{
"type": "subscription",
"external_id": "PREMIUM-MONTHLY",
"expiration_date": "2025-01-31"
}
]
}
]
}'
Response
Success Response (200 OK)
{
"data": {
"total": 3,
"created": 3,
"failed": 0,
"orders": [
{
"id": "12345",
"uuid": "275ca6c4-a815-4f64-8198-759a296dd495",
"external_id": "PROMO-001",
"status": "approved"
},
{
"id": "12346",
"uuid": "385da7d5-b926-5g75-9309-86a307dd596",
"external_id": "PROMO-002",
"status": "approved"
},
{
"id": "12347",
"uuid": "495eb8e6-ca37-6h86-0410-97b418ee6a7",
"external_id": "PROMO-003",
"status": "approved"
}
]
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
total | integer | Total number of orders in request |
created | integer | Number of successfully created orders |
failed | integer | Number of failed orders |
orders | array | Created orders with id, uuid, external_id, status |
errors | array | Only present if there are failures |
The bulk response returns minimal order data for performance. To get full order details including user and products, use the Get Order or List Orders endpoints after creation.
Partial Success Handling
Bulk operations support partial success. Some orders may succeed while others fail:
{
"data": {
"total": 3,
"created": 2,
"failed": 1,
"orders": [
{
"id": "12345",
"uuid": "275ca6c4-a815-4f64-8198-759a296dd495",
"external_id": "ORDER-001",
"status": "approved"
},
{
"id": "12346",
"uuid": "385da7d5-b926-5g75-9309-86a307dd596",
"external_id": "ORDER-003",
"status": "approved"
}
],
"errors": [
{
"index": 1,
"external_id": "ORDER-002",
"errors": {
"products.0.external_id": ["The product does not exist."]
}
}
]
}
}
Successfully validated orders are created even if other orders in the batch fail. Check the failed count and errors array to identify and retry failed orders.
Error Handling
Validation Errors (422)
{
"message": "The given data was invalid.",
"errors": {
"orders": ["The orders field is required."],
"orders.0.type": ["The orders.0.type field is required."],
"orders.1.products.0.external_id": ["The product does not exist."]
}
}
Too Many Orders (422)
{
"message": "The given data was invalid.",
"errors": {
"orders": ["The orders may not have more than 100 items."]
}
}
Common Error Causes
| Error | Cause |
|---|---|
orders field is required | Missing orders array |
orders must be an array | orders is not an array |
orders may not have more than 100 items | Exceeded 100 order limit |
orders.N.type is required | Order at index N missing type |
orders.N.products.M.external_id does not exist | Product at index M of order N not found |
Best Practices
1. Validate Before Submitting
Pre-validate your orders client-side to avoid partial failures:
// Example: validate all products exist before bulk submission
const productIds = orders.flatMap(o => o.products.map(p => p.external_id));
const validProducts = await validateProducts(productIds);
if (!validProducts.allExist) {
throw new Error('Invalid product IDs: ' + validProducts.missing.join(', '));
}
2. Batch Large Imports
For more than 100 orders, split into batches:
const BATCH_SIZE = 100;
const batches = chunk(orders, BATCH_SIZE);
for (const batch of batches) {
await createBulkOrders(batch);
}
3. Use Unique External References
Ensure each order has a unique external_id:
orders.forEach((order, index) => {
order.external_id = `IMPORT-${Date.now()}-${index}`;
});
4. Track Progress
For large imports, track which batches succeeded:
const results = [];
for (let i = 0; i < batches.length; i++) {
try {
const result = await createBulkOrders(batches[i]);
results.push({ batch: i, success: true, data: result });
} catch (error) {
results.push({ batch: i, success: false, error: error.message });
}
}
Performance Considerations
| Aspect | Recommendation |
|---|---|
| Batch size | Use 50-100 orders for optimal throughput |
| Retry logic | Implement exponential backoff for rate limiting |
| Parallel requests | Avoid parallel bulk requests; process sequentially |
| Timeout | Allow 30+ seconds for large batches |
Use Cases
Corporate Onboarding
Grant access to all employees at once:
{
"orders": [
{
"type": "permission",
"external_id": "CORP-EMP-001",
"user": { "email": "[email protected]" },
"products": [{ "type": "subscription", "external_id": "ENTERPRISE-PLAN" }]
},
{
"type": "permission",
"external_id": "CORP-EMP-002",
"user": { "email": "[email protected]" },
"products": [{ "type": "subscription", "external_id": "ENTERPRISE-PLAN" }]
}
]
}
Promotional Campaign
Mass distribution of free content:
{
"orders": [
{
"type": "permission",
"external_id": "PROMO-NEWSLETTER-001",
"user": { "email": "[email protected]" },
"products": [
{ "type": "content", "external_id": "FREE-SAMPLE-CHAPTER", "expiration_date": "2025-02-28" }
]
}
]
}
Migration from Legacy System
Import existing access records:
{
"orders": [
{
"type": "permission",
"external_id": "LEGACY-12345",
"user": { "id": "legacy-user-001", "email": "[email protected]" },
"products": [
{ "type": "content", "external_id": "EBOOK-001" },
{ "type": "content", "external_id": "EBOOK-002" }
]
}
]
}
See Also
- Permission Orders - Individual permission order creation
- Report Orders - Individual report order creation
- List Orders - Query created orders