Exporting Data from Gravity Rail
This guide shows you how to extract data from Gravity Rail, including reading records via APIs, exporting to CSV, and subscribing to real-time updates via webhooks.
In the product, builders export from the workspace UI — see Import & Export and Forms in the user guide.
Querying Data via API
Basic Record Query
Retrieve records from a data type:
curl "https://api.gravityrail.com/api/v2/w/{workspace_uuid}/data-types/{data_type_id}/records" \
-H "Authorization: Bearer YOUR_API_KEY"
Response:
{
"items": [
{
"id": 789,
"dataTypeId": 123,
"memberId": 42,
"externalId": "cust_001",
"fieldValues": {
"first_name": "Alice",
"email": "alice@example.com",
"status": "active"
},
"createdAt": "2024-01-15T10:00:00Z",
"updatedAt": "2024-01-20T15:30:00Z"
}
],
"total": 1,
"page": 1,
"pageSize": 50
}
Filtering Records
Filter by field values:
# Find by field value
curl "https://api.gravityrail.com/api/v2/w/{workspace_uuid}/data-types/123/records?email=alice@example.com" \
-H "Authorization: Bearer YOUR_API_KEY"
# Find by external ID (fast lookup)
curl "https://api.gravityrail.com/api/v2/w/{workspace_uuid}/data-types/123/records?externalId=cust_001" \
-H "Authorization: Bearer YOUR_API_KEY"
# Multiple field filters
curl "https://api.gravityrail.com/api/v2/w/{workspace_uuid}/data-types/123/records?status=active&company=Acme" \
-H "Authorization: Bearer YOUR_API_KEY"
Pagination
Retrieve large datasets in pages:
# Get page 2, 100 items per page
curl "https://api.gravityrail.com/api/v2/w/{workspace_uuid}/data-types/123/records?page=2&pageSize=100" \
-H "Authorization: Bearer YOUR_API_KEY"
Pagination parameters:
page- Page number (1-indexed, default: 1)pageSize- Records per page (default: 50, max: 1000)total- Total record count (included in response)
Sorting
Sort records by field or date:
# Sort by creation date, newest first
curl "https://api.gravityrail.com/api/v2/w/{workspace_uuid}/data-types/123/records?sortBy=createdAt&sortOrder=desc" \
-H "Authorization: Bearer YOUR_API_KEY"
# Sort by field value
curl "https://api.gravityrail.com/api/v2/w/{workspace_uuid}/data-types/123/records?sortBy=last_name&sortOrder=asc" \
-H "Authorization: Bearer YOUR_API_KEY"
Querying Collections
For data types with isCollection: true, retrieve all records of a type:
# Get all visit records for a patient
curl "https://api.gravityrail.com/api/v2/w/{workspace_uuid}/data-types/456/records?patient_id=42" \
-H "Authorization: Bearer YOUR_API_KEY"
Exporting Data to CSV
Export Members
Export member list with customizable fields:
curl -X POST "https://api.gravityrail.com/api/v2/w/{workspace_uuid}/members/export" \
-H "Authorization: Bearer YOUR_API_KEY" \
-o members.csv
Customizing export fields:
# Select specific fields
curl -X POST "https://api.gravityrail.com/api/v2/w/{workspace_uuid}/members/export?selected_fields=id&selected_fields=email&selected_fields=name&selected_fields=date_of_birth&selected_fields=labels" \
-H "Authorization: Bearer YOUR_API_KEY" \
-o members.csv
# Include data type records
curl -X POST "https://api.gravityrail.com/api/v2/w/{workspace_uuid}/members/export?selected_data_types=1&selected_data_types=2" \
-H "Authorization: Bearer YOUR_API_KEY" \
-o members.csv
Default export fields:
idexternal_idnamedate_of_birthemailphonenotify_smsnotify_emailnotify_voicelabels
CSV Output Example:
id,external_id,name,date_of_birth,email,phone,notify_email,notify_sms,notify_voice,labels
1,user_001,Alice Johnson,1980-06-15,alice@example.com,+1-555-001-0001,1,1,0,"vip,premium"
2,user_002,Bob Smith,1991-11-03,bob@example.com,+1-555-001-0002,1,0,1,standard
Export Data Records via UI
Export a data type's records to CSV:
- Navigate to Data > Forms > [Data Type Name]
- In the Entries tab, click the Export button
- Select which fields to include (optional)
- Download the CSV
Via API:
# Export all customer records
curl "https://api.gravityrail.com/api/v2/w/{workspace_uuid}/data-types/123/records/export" \
-H "Authorization: Bearer YOUR_API_KEY" \
-o customers.csv
Export Format:
id,first_name,last_name,email,phone,company,status,createdAt,updatedAt
1,Alice,Johnson,alice@example.com,+1-555-001-0001,Acme Inc,active,2024-01-15T10:00:00Z,2024-01-20T15:30:00Z
2,Bob,Smith,bob@example.com,+1-555-001-0002,TechCorp,inactive,2024-01-16T11:00:00Z,2024-01-21T12:00:00Z
Real-Time Updates with Webhooks
Webhooks allow you to subscribe to Gravity Rail events and receive real-time notifications when data changes.
Understanding Webhooks
A webhook is an HTTP callback that Gravity Rail sends to your server when an event occurs:
Your Event Handler
↑
│ (POST request)
│
Gravity Rail Event
│
└─→ Data Created/Updated/Deleted
Setting Up Webhooks
1. Create a Webhook Endpoint
Your endpoint should accept POST requests and handle webhook events:
# FastAPI example
from fastapi import FastAPI, Request
import json
app = FastAPI()
@app.post("/webhooks/gravity-rail")
async def handle_webhook(request: Request):
# Parse event
event = await request.json()
# The event type is in the top-level "event" field
if event["event"] == "data_record:created":
print(f"New record: {event['dataRecord']['fields']}")
elif event["event"] == "data_record:updated":
print(f"Record updated: {event['dataRecord']['id']}")
return {"status": "ok"}
2. Register the Webhook via Event Rules
Create a webhook subscription using Event Rules:
curl -X POST https://api.gravityrail.com/api/v2/w/{workspace_uuid}/event-rules \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Send data to webhook",
"eventType": "data_record:created",
"actionType": "webhook:send",
"actionParams": {
"webhookUrl": "https://your-app.com/webhooks/gravity-rail",
"signingSecret": "whsec_your_secret"
}
}'
Or via the UI:
- Navigate to workspace Settings > Apps
- Scroll to Event Rules or Webhooks
- Click + Add Rule or + Add Webhook
- Select the event type to trigger on
- Enter your endpoint URL
- Configure any filters (optional)
- Save
3. Webhook Security
When a webhook action has a signing secret configured, Gravity Rail signs every delivery with HMAC-SHA256 in an X-Webhook-Signature header (t={unix_timestamp},v1={hex_digest}). Verify the signature and reject deliveries whose timestamp is more than five minutes old. Keep the webhook URL secret as well — treat it like a password.
For the full verification recipe (Python and Node.js), see the canonical Webhooks reference.
Webhook Events and Payload Shapes
The event type is always in the top-level event field (for example data_record:created, member:updated, call:completed). Every payload also carries eventId, eventRule, and workspace blocks. The rest of the body takes one of five shapes by event family — data record, member, voicemail, fax, and the lean shape every other event uses.
The three shapes most relevant to data export are shown below. For the voicemail and fax shapes, the per-event catalog, and the complete field reference, see the canonical Webhooks reference.
Data record events (data_record:created, data_record:updated, data_record:changed)
data_record:changed is the canonical combined trigger. Its payload adds a
top-level operation field set to created or updated; the remainder of the
payload has the same shape below. Existing create/update triggers remain
available and continue to fire independently.
{
"event": "data_record:created",
"dataType": {
"uuid": "5f3c…",
"type": "Customer",
"slug": "customer"
},
"member": {
"id": 42,
"name": "Alice Johnson",
"email": "alice@example.com",
"phone": "+15551234567",
"externalId": "cust_001",
"labels": ["vip", "premium"],
"createdAt": "2026-01-15T10:30:00+00:00",
"updatedAt": "2026-01-15T10:30:00+00:00"
},
"dataRecord": {
"id": 789,
"externalId": "cust_001",
"fields": {
"first_name": "Alice",
"email": "alice@example.com",
"status": "active"
},
"createdAt": "2026-01-15T10:30:00+00:00",
"updatedAt": "2026-01-15T10:30:00+00:00"
},
"eventRule": { "id": 88, "uuid": "a1b2…", "name": "Send data to webhook" },
"author": { "id": 5, "accountUuid": "c4d5…", "name": "Operator", "email": "ops@acme.example" },
"workspace": { "uuid": "550e8400-e29b-41d4-a716-446655440000", "name": "Acme Health" }
}
dataRecord.fields holds the form's submitted values keyed by field slug. member is the record owner; author is whoever triggered the event.
Member events (member:updated)
{
"event": "member:updated",
"member": {
"id": 42,
"accountUuid": "c4d5…",
"name": "Alice Johnson",
"phone": "+15551234567",
"email": "alice@example.com",
"externalId": "cust_001",
"labels": ["vip", "premium"],
"role": "patient",
"createdAt": "2026-01-15T10:30:00+00:00",
"updatedAt": "2026-01-20T15:30:00+00:00"
},
"eventRule": { "id": 88, "uuid": "a1b2…", "name": "Sync label changes" },
"author": { "id": 5, "accountUuid": "c4d5…", "name": "Operator", "email": "ops@acme.example" },
"workspace": { "uuid": "550e8400-e29b-41d4-a716-446655440000", "name": "Acme Health" },
"context": {
"labelChanges": { "addedLabels": ["vip"], "removedLabels": [] }
}
}
Call and chat events (call:completed, call:started, chat:created, …)
These use a leaner shape and, when scoped to a chat, include a chat block with the chat's identifiers:
{
"event": "call:completed",
"eventRule": { "id": 88, "uuid": "a1b2…", "name": "Export call to data warehouse" },
"workspace": { "uuid": "550e8400-e29b-41d4-a716-446655440000", "name": "Acme Health" },
"member": { "id": 42, "accountUuid": "c4d5…", "email": "alice@example.com" },
"chat": { "id": 73219, "uuid": "f7a9…" }
}
The recording URL is never included — recordings are PHI. Use the integer chat.id to fetch the call's audio and transcript over your own authenticated chats:read request. See Fetching call audio and transcript in the Webhooks reference.
For the complete payload field reference and signature-verification code, see the canonical Webhooks reference.
Event Rules (Advanced Webhook Triggers)
Create sophisticated automation rules that trigger webhooks based on conditions:
curl -X POST https://api.gravityrail.com/api/v2/w/{workspace_uuid}/event-rules \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "High-Value Customer Alert",
"eventType": "data_record:created",
"conditions": "dataRecord.fields.amount > 1000",
"actionType": "webhook:send",
"actionParams": {
"webhookUrl": "https://your-app.com/webhooks/high-value-orders",
"signingSecret": "whsec_your_secret"
}
}'
See the Event Rules Guide for complete documentation.
Data Export Workflows
Complete Data Backup
Export all data from your workspace:
#!/bin/bash
WORKSPACE_UUID="550e8400-e29b-41d4-a716-446655440000"
API_KEY="your_api_key"
EXPORT_DIR="./backup_$(date +%Y%m%d)"
mkdir -p "$EXPORT_DIR"
# Export members
curl "https://api.gravityrail.com/api/v2/w/${WORKSPACE_UUID}/members/export" \
-H "Authorization: Bearer ${API_KEY}" \
-o "$EXPORT_DIR/members.csv"
# Export each data type
DATA_TYPES=$(curl "https://api.gravityrail.com/api/v2/w/${WORKSPACE_UUID}/data-types" \
-H "Authorization: Bearer ${API_KEY}" | jq -r '.[] | .slug')
for slug in $DATA_TYPES; do
curl "https://api.gravityrail.com/api/v2/w/${WORKSPACE_UUID}/data-types/${slug}/records/export" \
-H "Authorization: Bearer ${API_KEY}" \
-o "$EXPORT_DIR/${slug}.csv"
done
tar czf "backup_${WORKSPACE_UUID}_$(date +%Y%m%d).tar.gz" "$EXPORT_DIR"
rm -rf "$EXPORT_DIR"
echo "Backup complete"
Sync Data to External System
Export and sync Gravity Rail data to your external database:
import requests
import json
def sync_gravity_rail_to_postgres():
"""Sync customer data from Gravity Rail to PostgreSQL"""
api_key = "your_api_key"
workspace_uuid = "your_workspace_uuid"
# Fetch all customer records
response = requests.get(
f"https://api.gravityrail.com/api/v2/w/{workspace_uuid}/data-types/123/records?pageSize=1000",
headers={"Authorization": f"Bearer {api_key}"}
)
records = response.json()["items"]
# Insert/update in PostgreSQL
for record in records:
cursor.execute("""
INSERT INTO customers (gravity_id, email, name, status, updated_at)
VALUES (%s, %s, %s, %s, %s)
ON CONFLICT (gravity_id) DO UPDATE SET
email = EXCLUDED.email,
name = EXCLUDED.name,
status = EXCLUDED.status,
updated_at = EXCLUDED.updated_at
""", (
record["id"],
record["fieldValues"]["email"],
record["fieldValues"]["name"],
record["fieldValues"]["status"],
record["updatedAt"]
))
conn.commit()
print(f"Synced {len(records)} records")
Real-Time Data Pipeline
Use webhooks to build a real-time data pipeline:
# When a customer record is created in Gravity Rail,
# automatically send them a welcome email and create an account in Stripe
from fastapi import FastAPI
import stripe
import smtplib
app = FastAPI()
@app.post("/webhooks/gravity-rail")
async def handle_customer_created(request: Request):
event = await request.json()
if event["event"] != "data_record:created" or event["dataType"]["slug"] != "customer":
return {"status": "ok"}
customer = event["dataRecord"]["fields"]
# Create Stripe customer
stripe_customer = stripe.Customer.create(
email=customer["email"],
name=customer["name"],
metadata={"gravity_id": event["dataRecord"]["id"]}
)
# Send welcome email
send_email(
to=customer["email"],
subject="Welcome!",
body=f"Hello {customer['name']}, welcome to our platform!"
)
return {"status": "processed"}
Monitoring Webhook Delivery
View Webhook Logs
Check webhook delivery status in the UI:
- Navigate to workspace Settings > Apps > Webhook Logs
- View recent webhook deliveries, successes, and failures
- Debug failed webhooks by viewing request/response details
Via API
# Get webhook logs for a specific event type (requires the webhooks:read scope)
curl "https://api.gravityrail.com/api/v2/w/{workspace_uuid}/webhook-logs?eventType=data_record:created&success=false" \
-H "Authorization: Bearer YOUR_API_KEY"
Response:
{
"items": [
{
"id": 1,
"ruleId": 88,
"eventType": "data_record:created",
"url": "https://your-app.com/webhooks/gravity-rail",
"success": true,
"statusCode": 200,
"createdAt": "2026-01-15T10:30:00Z"
},
{
"id": 2,
"ruleId": 88,
"eventType": "data_record:created",
"url": "https://your-app.com/webhooks/gravity-rail",
"success": false,
"statusCode": 500,
"errorMessage": "HTTP 500: Internal Server Error",
"createdAt": "2026-01-15T10:31:00Z"
}
]
}
Retry Failed Webhooks
Gravity Rail automatically retries failed deliveries up to 5 times with exponential backoff — the first retry after 10 seconds, then doubling (10s, 20s, 40s, 80s, capped at 5 minutes) — before marking the delivery failed. There is no manual retry endpoint, so design your handler to be idempotent so replays are safe.
Best Practices
API Querying
- Use pagination: Don't fetch all records at once; use pagination with sensible page sizes
- Filter early: Use API filters to reduce data transferred
- Index your queries: Mark fields as indexed if you frequently search/filter by them
- Cache results: If data doesn't change frequently, cache API responses locally
CSV Exports
- Schedule regular exports: Automate backups of your data
- Version exports: Include timestamps in filenames (e.g.,
customers_2024-01-20.csv) - Validate data: After export, validate that records match expectations
- Archive old exports: Keep backups, but manage storage
Webhook Integration
- Idempotency: Design handlers to safely process the same event twice (webhooks may be retried)
- Fast responses: Return quickly (within 30 seconds) and process asynchronously if needed
- Verify signatures: Verify the
X-Webhook-SignatureHMAC-SHA256 header on every delivery and reject deliveries whose timestamp is more than five minutes old; keep your webhook URL secret as well - Error handling: Log failures and implement retry logic in your handler
- Monitor logs: Regularly check webhook logs to detect delivery issues
Example: Building an Analytics Pipeline
# Use webhooks to feed data into your analytics system
import logging
logger = logging.getLogger(__name__)
@app.post("/webhooks/analytics")
async def handle_event(request: Request):
"""
Receive Gravity Rail events and send to analytics pipeline
"""
event = await request.json()
# Send to analytics (BigQuery, Segment, etc.)
send_to_analytics({
"event_type": event["event"],
"workspace_id": event["workspace"]["uuid"],
"rule_id": event["eventRule"]["id"],
"payload": event,
})
return {"status": "processed"}
API Reference
For complete API documentation, see API Reference.
Key endpoints:
GET /w/{workspace_uuid}/data-types/{data_type_id}/records- Query recordsPOST /w/{workspace_uuid}/members/export- Export members to CSVGET /w/{workspace_uuid}/data-types/{data_type_id}/records/export- Export data type records to CSVGET /w/{workspace_uuid}/webhook-logs- View webhook logsGET /w/{workspace_uuid}/event-rules- List event rulesPOST /w/{workspace_uuid}/event-rules- Create event rule (for webhook subscriptions)