Skip to main content

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

FieldTypeDescription
ordersarrayArray of order objects (1-100 orders)

Each order object follows the same structure as individual order creation. See:

Limits

LimitValue
Maximum orders per request100
Minimum orders per request1

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

FieldTypeDescription
totalintegerTotal number of orders in request
createdintegerNumber of successfully created orders
failedintegerNumber of failed orders
ordersarrayCreated orders with id, uuid, external_id, status
errorsarrayOnly present if there are failures
Retrieving Full Order Details

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."]
}
}
]
}
}
Partial Success

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

ErrorCause
orders field is requiredMissing orders array
orders must be an arrayorders is not an array
orders may not have more than 100 itemsExceeded 100 order limit
orders.N.type is requiredOrder at index N missing type
orders.N.products.M.external_id does not existProduct 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

AspectRecommendation
Batch sizeUse 50-100 orders for optimal throughput
Retry logicImplement exponential backoff for rate limiting
Parallel requestsAvoid parallel bulk requests; process sequentially
TimeoutAllow 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


X

Graph View