Export Data from ODP
Why data export matters
Section titled “Why data export matters”ODP collects rich customer data — events, profiles, segments, computed metrics — but that data is most valuable when it flows into your broader data infrastructure. Your BI team needs it in the data warehouse for cross-system reporting. Your data science team needs it for predictive models. Your CRM needs segment membership updates to trigger workflows.
Without export, ODP becomes a data silo. With export, it becomes a hub that enriches every downstream system with unified customer intelligence.
What you will do
Section titled “What you will do”- Choose the right export method for your use case
- Query customer profiles and events via the API
- Set up webhooks for real-time segment change notifications
- Configure batch exports for data warehouse ingestion
- Handle privacy and consent requirements in exported data
Choose your export method
Section titled “Choose your export method”| Method | Best for | Latency | Volume |
|---|---|---|---|
| REST API | On-demand lookups, application integrations | Real-time | Individual records |
| Webhooks | Reacting to segment entry/exit, event triggers | Near real-time (seconds) | Event-driven |
| Batch export | Data warehouse loads, BI reporting, bulk analysis | Scheduled (hourly/daily) | High volume |
When to use each
Section titled “When to use each”- REST API — Your application needs to look up a customer profile at runtime (e.g., personalization engine checking segment membership before rendering a page).
- Webhooks — You need to trigger an action when something happens (e.g., send a Slack alert when a high-value customer enters the “at-risk churn” segment).
- Batch export — You need to load all customer data into a warehouse on a regular schedule for reporting and analysis.
Export via REST API
Section titled “Export via REST API”Query a customer profile
Section titled “Query a customer profile”Look up a customer profile by any known identifier:
const fetch = require('node-fetch');
async function getCustomerProfile(identifier, value) {
const response = await fetch(
`https://api.zaius.com/v3/profiles?id_field=${identifier}&id_value=${value}`,
{
headers: {
'x-api-key': process.env.ODP_PRIVATE_API_KEY
}
}
);
return response.json();
}
// Look up by email
const profile = await getCustomerProfile('email', 'customer@example.com');
console.log('Segments:', profile.segments);
console.log('Lifetime value:', profile.attributes.lifetime_value);
// Look up by customer ID
const profileById = await getCustomerProfile(
'customer_id', 'CUST-9876'
); import requests
import os
def get_customer_profile(
identifier: str, value: str
) -> dict:
response = requests.get(
'https://api.zaius.com/v3/profiles',
params={
'id_field': identifier,
'id_value': value
},
headers={
'x-api-key': os.environ['ODP_PRIVATE_API_KEY']
}
)
response.raise_for_status()
return response.json()
# Look up by email
profile = get_customer_profile(
'email', 'customer@example.com'
)
print(f'Segments: {profile["segments"]}')
print(f'LTV: {profile["attributes"]["lifetime_value"]}') curl -G https://api.zaius.com/v3/profiles \
-H 'x-api-key: YOUR_PRIVATE_API_KEY' \
-d 'id_field=email' \
-d 'id_value=customer@example.com' Query events for a customer
Section titled “Query events for a customer”Retrieve the event history for a specific customer:
async function getCustomerEvents(
identifier, value, eventType
) {
const params = new URLSearchParams({
id_field: identifier,
id_value: value,
...(eventType && { event_type: eventType }),
limit: '50'
});
const response = await fetch(
`https://api.zaius.com/v3/events?${params}`,
{
headers: {
'x-api-key': process.env.ODP_PRIVATE_API_KEY
}
}
);
return response.json();
}
// Get all events for a customer
const allEvents = await getCustomerEvents(
'email', 'customer@example.com'
);
// Get only purchase events
const purchases = await getCustomerEvents(
'email', 'customer@example.com', 'order'
); def get_customer_events(
identifier: str,
value: str,
event_type: str = None
) -> dict:
params = {
'id_field': identifier,
'id_value': value,
'limit': 50
}
if event_type:
params['event_type'] = event_type
response = requests.get(
'https://api.zaius.com/v3/events',
params=params,
headers={
'x-api-key': os.environ['ODP_PRIVATE_API_KEY']
}
)
response.raise_for_status()
return response.json()
# Get purchase events
purchases = get_customer_events(
'email', 'customer@example.com',
event_type='order'
) curl -G https://api.zaius.com/v3/events \
-H 'x-api-key: YOUR_PRIVATE_API_KEY' \
-d 'id_field=email' \
-d 'id_value=customer@example.com' \
-d 'event_type=order' \
-d 'limit=50' Export segment membership
Section titled “Export segment membership”List all customers in a specific segment:
async function exportSegmentMembers(
segmentId, cursor = null
) {
const params = new URLSearchParams({
segment_id: segmentId,
limit: '1000'
});
if (cursor) params.set('cursor', cursor);
const response = await fetch(
`https://api.zaius.com/v3/profiles/export?${params}`,
{
headers: {
'x-api-key': process.env.ODP_PRIVATE_API_KEY
}
}
);
return response.json();
}
// Paginate through all segment members
let cursor = null;
let allMembers = [];
do {
const batch = await exportSegmentMembers(
'seg_abc123', cursor
);
allMembers = allMembers.concat(batch.profiles);
cursor = batch.next_cursor;
} while (cursor);
console.log(`Total members: ${allMembers.length}`); def export_segment_members(
segment_id: str
) -> list:
all_members = []
cursor = None
while True:
params = {
'segment_id': segment_id,
'limit': 1000
}
if cursor:
params['cursor'] = cursor
response = requests.get(
'https://api.zaius.com/v3/profiles/export',
params=params,
headers={
'x-api-key': os.environ['ODP_PRIVATE_API_KEY']
}
)
response.raise_for_status()
data = response.json()
all_members.extend(data['profiles'])
cursor = data.get('next_cursor')
if not cursor:
break
return all_members
members = export_segment_members('seg_abc123')
print(f'Total members: {len(members)}') curl -G https://api.zaius.com/v3/profiles/export \
-H 'x-api-key: YOUR_PRIVATE_API_KEY' \
-d 'segment_id=seg_abc123' \
-d 'limit=1000' Export via webhooks
Section titled “Export via webhooks”Webhooks push data to your systems in real time when events occur. Configure them in ODP Settings > Webhooks.
Set up a segment webhook
Section titled “Set up a segment webhook”Segment webhooks fire when customers enter or exit a segment:
- Navigate to Settings > Webhooks in ODP
- Click Create Webhook
- Set the Trigger to Segment Entry or Segment Exit
- Select the target segment
- Enter your endpoint URL (must accept POST requests over HTTPS)
- Optionally add authentication headers
- Save and test with a sample payload
Handle webhook payloads
Section titled “Handle webhook payloads”Your endpoint receives a POST request with a JSON body:
const express = require('express');
const app = express();
app.post('/webhooks/odp', express.json(), (req, res) => {
const { event_type, customer, segment } = req.body;
console.log(`Customer ${customer.email}`);
console.log(`${event_type} segment: ${segment.name}`);
switch (event_type) {
case 'segment_entry':
// Customer entered a segment
triggerWelcomeEmail(customer.email, segment.name);
break;
case 'segment_exit':
// Customer left a segment
removeFromCampaign(customer.email, segment.name);
break;
}
// Respond quickly to acknowledge receipt
res.status(200).json({ received: true });
});
app.listen(3000); from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/webhooks/odp', methods=['POST'])
def handle_odp_webhook():
payload = request.get_json()
event_type = payload['event_type']
customer = payload['customer']
segment = payload['segment']
print(f'Customer {customer["email"]}')
print(f'{event_type} segment: {segment["name"]}')
if event_type == 'segment_entry':
trigger_welcome_email(
customer['email'], segment['name']
)
elif event_type == 'segment_exit':
remove_from_campaign(
customer['email'], segment['name']
)
return jsonify({'received': True}), 200 Webhook reliability tips:
- Respond with a 2xx status within 5 seconds. Do heavy processing asynchronously.
- ODP retries failed deliveries (non-2xx or timeout) with exponential backoff.
- Implement idempotency — the same event may be delivered more than once.
Batch export to data warehouses
Section titled “Batch export to data warehouses”For high-volume data warehouse loads, use the ODP batch export feature.
Supported destinations
Section titled “Supported destinations”| Destination | Connection method |
|---|---|
| Amazon S3 | IAM role or access key credentials |
| Google BigQuery | Service account with BigQuery write access |
| Snowflake | Snowflake connector with warehouse and schema details |
| Azure Blob Storage | Storage account key or SAS token |
| SFTP | SSH key or username/password |
Configure a batch export
Section titled “Configure a batch export”- Navigate to Settings > Data Export in ODP
- Click Create Export
- Select the data type: Customer Profiles, Events, or Segment Membership
- Choose your destination and provide connection credentials
- Set the schedule: hourly, daily, or weekly
- Select which fields to include (or export all)
- Choose the file format: CSV, JSON, or Parquet
- Save and run a test export
Common use cases
Section titled “Common use cases”| Use case | Data to export | Schedule | Destination |
|---|---|---|---|
| BI dashboards | Customer profiles + events | Daily | BigQuery or Snowflake |
| Data science models | Full event history | Weekly | S3 as Parquet |
| CRM sync | Segment membership changes | Hourly | SFTP to CRM import |
| Compliance audit | All customer data with consent status | Monthly | Secure S3 bucket |
| Marketing reporting | Campaign events + conversions | Daily | BigQuery |
Privacy considerations
Section titled “Privacy considerations”Exported data contains customer information. Handle it responsibly.
Consent status
Section titled “Consent status”Include consent fields in exports so downstream systems can respect customer preferences:
- marketing_consent — Whether the customer opted in to marketing communications
- tracking_consent — Whether the customer consented to behavioral tracking
- data_processing_consent — Whether the customer consented to data processing (GDPR)
Data minimization
Section titled “Data minimization”Export only the fields you need. If your BI dashboard does not require email addresses, exclude PII from the export. This reduces risk if the destination system is compromised.
Retention alignment
Section titled “Retention alignment”Ensure exported data follows the same retention policies as ODP. If ODP deletes customer data after 24 months, configure your warehouse to apply the same retention.
Deletion propagation
Section titled “Deletion propagation”When a customer exercises their right to deletion (GDPR Article 17, CCPA), you must delete their data from all systems — including exported copies. Plan for this:
- Track which systems received exported data
- Implement a deletion workflow that propagates ODP deletion requests to all downstream systems
- Use the ODP Deletion API to trigger the process
async function deleteCustomerData(email) {
// Delete from ODP
const response = await fetch(
'https://api.zaius.com/v3/profiles/delete',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': process.env.ODP_PRIVATE_API_KEY
},
body: JSON.stringify({
id_field: 'email',
id_value: email
})
}
);
if (response.ok) {
// Propagate deletion to downstream systems
await deleteFromWarehouse(email);
await deleteFromCRM(email);
console.log(`Deletion complete for ${email}`);
}
} def delete_customer_data(email: str) -> None:
# Delete from ODP
response = requests.post(
'https://api.zaius.com/v3/profiles/delete',
headers={
'Content-Type': 'application/json',
'x-api-key': os.environ['ODP_PRIVATE_API_KEY']
},
json={
'id_field': 'email',
'id_value': email
}
)
response.raise_for_status()
# Propagate deletion to downstream systems
delete_from_warehouse(email)
delete_from_crm(email)
print(f'Deletion complete for {email}') curl -X POST https://api.zaius.com/v3/profiles/delete \
-H 'Content-Type: application/json' \
-H 'x-api-key: YOUR_PRIVATE_API_KEY' \
-d '{
"id_field": "email",
"id_value": "customer@example.com"
}' Troubleshooting
Section titled “Troubleshooting”| Issue | Cause | Fix |
|---|---|---|
| API returns 401 Unauthorized | Invalid or expired API key | Regenerate the private API key in ODP Settings > API Keys |
| API returns 429 Too Many Requests | Rate limit exceeded | Implement exponential backoff; default limit is 100 requests/second |
| Webhook not firing | Endpoint unreachable or returning non-2xx | Check endpoint URL is publicly accessible over HTTPS; verify in webhook logs |
| Webhook payload missing fields | Fields not tracked or customer not identified | Verify event tracking includes expected properties; check identity resolution |
| Batch export produces empty files | No data matches the export criteria | Verify date range, segment filter, and field selection; check that data exists in ODP |
| Batch export credentials fail | Destination permissions incorrect | Verify IAM role, service account, or access key has write permission to the destination |
| Exported PII after deletion request | Deletion not propagated to export destination | Implement deletion propagation workflow; re-run deletion in downstream systems |