Events are the foundation of usage-based billing in FlexPrice. An event represents a single measurable activity from your application (e.g., API request, GB stored, compute minute).
Event Structure
Every event must include these required fields:
Field Type Required Description event_namestring Yes Identifier for the event type (e.g., api_request) external_customer_idstring Yes Customer ID in your system timestampISO 8601 Yes When the event occurred (UTC) propertiesobject No Custom event data for filtering and aggregation event_idstring No Idempotency key (auto-generated if omitted) customer_idstring No FlexPrice customer ID (resolved automatically) sourcestring No Event source identifier
Event Schema
Complete Event
Minimal Event
{
"event_name" : "api_request" ,
"external_customer_id" : "customer_123" ,
"timestamp" : "2024-03-20T15:04:05Z" ,
"event_id" : "evt_unique_12345" ,
"source" : "production-api" ,
"properties" : {
"endpoint" : "/api/v1/users" ,
"method" : "GET" ,
"response_time_ms" : 45 ,
"status_code" : 200 ,
"bytes_transferred" : 2048
}
}
Sending Events
Single Event Ingestion
Use POST /v1/events to send individual events:
curl -X POST https://us.api.flexprice.io/v1/events \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"event_name": "api_request",
"external_customer_id": "customer_123",
"timestamp": "2024-03-20T15:04:05Z",
"properties": {
"endpoint": "/api/v1/users",
"method": "GET"
}
}'
Response (HTTP 202):
{
"message" : "Event accepted for processing" ,
"event_id" : "evt_unique_12345"
}
Events are processed asynchronously . A 202 response means the event was accepted and queued, not that processing is complete. Processing typically completes within seconds.
Bulk Event Ingestion
For high-volume scenarios or backfilling historical data, use POST /v1/events/bulk:
curl -X POST https://us.api.flexprice.io/v1/events/bulk \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"events": [
{
"event_name": "api_request",
"external_customer_id": "customer_123",
"timestamp": "2024-03-20T15:04:05Z"
},
{
"event_name": "api_request",
"external_customer_id": "customer_456",
"timestamp": "2024-03-20T15:05:12Z"
}
]
}'
Limits:
Maximum 1,000 events per bulk request
For larger datasets, send multiple bulk requests
Response (HTTP 202):
{
"message" : "Events accepted for processing"
}
Event Properties
The properties field contains custom data specific to your event:
Best Practices
Use Consistent Property Names
Maintain consistent naming across events of the same type. Use snake_case for property keys.
Include Filterable Dimensions
Add properties you’ll use for filtering (region, product tier, feature flag, etc.).
Store Aggregatable Values
Include numeric fields you’ll aggregate (bytes, duration, count, etc.).
Keep Properties Flat
Nested objects work, but top-level properties are easier to filter and aggregate.
Example Properties by Use Case
API Metering
Storage Metering
Compute Metering
AI/ML Metering
{
"properties" : {
"endpoint" : "/api/v1/users" ,
"method" : "GET" ,
"response_time_ms" : 45 ,
"status_code" : 200 ,
"bytes_sent" : 1024 ,
"bytes_received" : 2048
}
}
Idempotency
FlexPrice uses event_id for idempotency to prevent duplicate billing:
{
"event_id" : "unique_key_from_your_system" ,
"event_name" : "api_request" ,
"external_customer_id" : "customer_123" ,
"timestamp" : "2024-03-20T15:04:05Z"
}
If you send the same event_id twice, only the first event is processed
If omitted, FlexPrice generates a UUID (no deduplication)
Use your own IDs (request ID, transaction ID) for guaranteed deduplication
Timestamps
Timestamps must be in ISO 8601 format with timezone:
{
"timestamp" : "2024-03-20T15:04:05Z"
}
Supported formats:
2024-03-20T15:04:05Z (UTC)
2024-03-20T15:04:05.123456789Z (with nanoseconds)
2024-03-20T15:04:05-07:00 (with timezone offset)
Backfilling Historical Events
You can send events with past timestamps for backfilling:
{
"event_name" : "api_request" ,
"external_customer_id" : "customer_123" ,
"timestamp" : "2024-01-01T00:00:00Z"
}
Backfilled events are processed normally and will affect usage calculations for their respective time periods. Ensure billing periods haven’t been finalized before backfilling.
Error Handling
Validation Errors (400)
{
"error" : "invalid request payload" ,
"hint" : "Invalid request payload" ,
"details" : {
"field" : "external_customer_id" ,
"error" : "required field missing"
}
}
Common validation errors:
Missing required fields (event_name, external_customer_id, timestamp)
Invalid timestamp format
Invalid data types in properties
Authentication Errors (401)
{
"error" : "unauthorized" ,
"hint" : "Invalid or missing API key"
}
Rate Limiting (429)
FlexPrice applies rate limits per tenant:
{
"error" : "rate limit exceeded" ,
"hint" : "Too many requests. Please try again later."
}
Implement exponential backoff when retrying:
import time
import random
def send_with_retry ( event , max_retries = 3 ):
for attempt in range (max_retries):
try :
return client.events.ingest_event( ** event)
except RateLimitError:
if attempt == max_retries - 1 :
raise
sleep_time = ( 2 ** attempt) + random.random()
time.sleep(sleep_time)
Querying Events
Retrieve raw events for debugging or export:
curl -X POST https://us.api.flexprice.io/v1/events/query \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"external_customer_id": "customer_123",
"event_name": "api_request",
"start_time": "2024-03-01T00:00:00Z",
"end_time": "2024-03-31T23:59:59Z",
"page_size": 50
}'
Response:
{
"events" : [
{
"id" : "evt_abc123" ,
"event_name" : "api_request" ,
"external_customer_id" : "customer_123" ,
"timestamp" : "2024-03-20T15:04:05Z" ,
"properties" : {
"endpoint" : "/api/v1/users" ,
"method" : "GET"
}
}
],
"has_more" : true ,
"total_count" : 150
}
See Query Events API for full documentation.
Best Practices
Send Events in Real-Time
Send events as they occur for accurate, up-to-date usage tracking. Don’t batch unnecessarily.
Use Bulk API for Historical Data
When backfilling or importing data, use /events/bulk for better performance.
Implement Retry Logic
Network failures happen. Retry failed requests with exponential backoff.
Set Idempotency Keys
Always provide event_id to prevent duplicate billing from retries.
Monitor Event Processing
Use the monitoring endpoint to track ingestion lag and event counts.
Validate Before Sending
Check for required fields and valid formats in your application before sending.
Next Steps
Configure Meters Create meters to aggregate events into usage
Aggregation Methods Learn about aggregation types
API Reference Full API documentation
Query Usage Retrieve aggregated usage