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

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_ref instead of internal_order_reference_identifier
  • Avoid redundant data - Don't duplicate information Commerce already stores
  • Prefer underscored values - warehouse_code: "wh_accra_01" instead of warehouse_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_line2 instead of nested objects

Attaching Custom Data

Include the custom_data parameter when creating or updating Commerce objects:

Attaching Custom Data

POST
/orders/new
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.


Was this page helpful?