Custom Data
Custom Data lets you attach string key-value pairs to Commerce objects—orders, customers, payments, and more. Use it to store reference IDs, external system identifiers, or small amounts of supplementary information that your application needs but Commerce doesn't use directly. This guide explains how Custom Data works, its constraints, and when to use it (or not).
How it works
Avoid data leakage: Custom data usage often leads to data leakage—developers store application-specific data in Commerce that doesn't belong there. Only give Commerce the data it needs to successfully perform the request. Your application's internal state, business logic, and implementation details should remain in your system. Commerce should only receive what's necessary for payment processing, order fulfillment, and customer communication.
Custom data is a simple string-to-string map attached to Commerce objects. You provide keys and values as strings, and Commerce stores them with the object. When you retrieve the object later, the custom data comes back exactly as you provided it—Commerce doesn't interpret, validate, or use this data for any purpose. The entire custom data object, when serialized to JSON, cannot exceed 25 KB. Both keys and values must be strings—Commerce returns a 400 Bad Request error if you provide non-string values like numbers, booleans, arrays, or objects.
Important design principle: Good API integration design usually doesn't require storing data in custom data fields. Over-reliance on custom data often signals architectural issues that should be addressed at the application level. If you find yourself storing significant amounts of data or complex structures in custom data, contact our technical support team to discuss better approaches.
When to use Custom Data
Use Custom Data sparingly for genuinely application-specific needs:
Appropriate uses:
- External reference IDs - Link Commerce objects to records in your system (
internal_order_id,crm_customer_id) - Simple flags - Store boolean-like values as strings (
requires_gift_wrap: "true",is_priority_customer: "yes") - Display hints - Store presentational information (
customer_tier: "gold",display_category: "electronics") - Tracking identifiers - Associate analytics or marketing tracking codes (
utm_campaign,affiliate_code)
When NOT to use Custom Data:
- ❌ Storing large amounts of data (use your own database)
- ❌ Complex nested objects or arrays (flatten to separate keys or store in your system)
- ❌ Frequently changing data (Custom Data updates require API calls)
- ❌ Data that needs to be queried or filtered (Commerce doesn't index Custom Data)
- ❌ Sensitive information like passwords or full credit card numbers (security risk)
Size constraints
What counts toward the limit:
- All key strings
- All value strings
- JSON formatting:
{,},:,,,"characters - Whitespace in the serialized JSON
Staying within the limit:
- Use short, meaningful keys -
order_refinstead ofinternal_order_reference_identifier - Avoid redundant data - Don't duplicate information Commerce already stores
- Prefer underscored values -
warehouse_code: "wh_accra_01"instead ofwarehouse_code: "Warehouse Location Accra Primary Facility" - Don't store large text - Descriptions, notes, or content belong in your database
- Flatten nested data - Use
address_line1,address_line2instead of nested objects
Attaching Custom Data
Include the custom_data parameter when creating or updating Commerce objects:
Attaching Custom Data
curl https://api.zebo.dev/orders/new \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"custom_data": {
"internal_order_id": "ORD-2025-1234",
"fulfillment_warehouse": "WH-ACCRA-01",
"shipping_priority": "standard"
},
...
}'
When you retrieve the object later, Custom Data is included in the response:
{
"order": {
"id": "or_abc123",
"status": "completed",
"custom_data": {
"internal_order_id": "ORD-2025-1234",
"fulfillment_warehouse": "WH-ACCRA-01",
"shipping_priority": "standard"
},
...
}
}
Updating Custom Data
Updating Custom Data replaces the entire Custom Data object—it doesn't merge with existing values. If you want to preserve existing keys, retrieve the object first, modify the Custom Data, then update.
Example: Adding a key while preserving existing data
Updating Custom Data
// Retrieve the order
const order = await client.orders.get('or_abc123')
// Modify Custom Data (preserves existing keys)
const updatedCustomData = {
...order.custom_data,
fulfillment_status: 'picked',
shipped_at: '2025-01-15T10:30:00Z',
}
// Update the order
await client.orders.update('or_abc123', {
custom_data: updatedCustomData,
})
Objects that support Custom Data
Most Commerce objects support Custom Data:
- Orders - Link to internal order management systems
- Customers - Store CRM references or customer segments
- Payments - Associate accounting or reconciliation identifiers
- Payment methods - Tag with usage hints or categorization
- Payouts - Connect to financial system records
- Chimes - Track campaign or notification context
Check the API reference for specific objects to confirm Custom Data support.
Design recommendations
Keep it minimal: The best integrations rarely use Custom Data. If you're storing more than 5-10 key-value pairs per object, reconsider your approach.
Use your database: Commerce is not a general-purpose data store. Store application data in your own database and use Custom Data only for linkage.
Avoid duplication: Don't store data that Commerce already provides (order status, customer email, payment amounts). Query the API for current values instead.
Plan for limits: Design assuming Custom Data might be unavailable or lossy. Your application should function without it.
Contact support: If you're unsure whether Custom Data is the right approach, or if you're hitting size limits, reach out to our technical support team. We can help you design a better solution.
Related resources
- Accept a payment - Creating orders with Custom Data
- Errors - Handling validation errors for Custom Data
- Authentication - Securing API requests