Klaviyo Events API: send custom events safely
Short answer. Define the event and identity contract before coding. Send server-authoritative events to
POST https://a.klaviyo.com/api/eventswith least-privilege authentication and a supportedrevisionheader. Include a stableunique_idfor idempotent retries, the actual eventtime, structured properties, and a profile identifier. Treat202 Acceptedas queued, handle429withRetry-After, monitor ingestion, and usebackfill: truefor historical replays that must not trigger flows.
Custom events let Klaviyo respond to product, subscription, account, marketplace, offline, or operational behavior that a native integration does not provide. The API call is the easy part. Reliable identity, semantics, retries, monitoring, and lifecycle ownership determine whether the event can safely trigger customer communication.
This guide was reviewed on November 3, 2026 against Klaviyo's official Events API overview, Create Event reference, rate-limit guide, versioning policy, and authentication guide, all reopened that day. Use the current reference for production code.
Start with an event contract
Create a tracking plan before an endpoint integration.
| Field | Example | Decision |
|---|---|---|
| Metric name | Report Generated |
Stable business meaning |
| Trigger moment | Report persisted successfully | Not button click or attempt |
| Profile identity | Internal user ID | Stable across email changes |
| Object context | workspace_id | Account or project relationship |
| Event time | Source occurrence in UTC | Not API delivery time |
| Unique ID | Source event UUID | Stable across retries |
| Required properties | report_type, project_id | Used by flow or analysis |
| Optional properties | source, template | Safe fallback if missing |
| Owner | Product data team | Monitors schema and delivery |
| Lifecycle uses | Activation flow, segment | Downstream dependencies |
An event name should describe something that happened. Use Subscription Canceled, not Subscription Status, and define whether it occurs when cancellation is requested or becomes effective.
Avoid changing semantics behind an existing metric. If the event meaning changes materially, version the source contract or create a new metric after a migration plan.
Event versus profile property
Events record occurrences with time and context. Profile properties represent current person-level state.
For a subscription:
- event:
Subscription Started,Renewal Failed,Subscription Paused; - profile property:
current_subscription_status = active; - event property: subscription ID, plan, amount, currency, failure reason.
Flows often need both. The trigger event provides immutable context, while the current profile state can stop a later message after the situation changes.
In our reading, update order matters: if the event reaches Klaviyo before a related profile update, a flow can evaluate stale state. Include essential context on the event or sequence the operations with tested behavior.
Choose a stable profile identity
The current Create Event endpoint requires at least one profile identifier such as Klaviyo profile ID, email, or phone number. Prefer a stable internal identifier or mapped Klaviyo ID where the architecture supports it. Email addresses change and can create identity fragmentation.
Document:
- source user or customer ID;
- mapping to Klaviyo profile;
- anonymous-to-known behavior;
- email and phone changes;
- guest checkout identity;
- merge, duplicate, and deletion handling;
- account or object relationship.
Do not use test domains such as example.com or test.com to validate ingestion. Klaviyo's current Events API documentation says events with those test-style addresses can return 202 and then be silently dropped. Use a controlled domain you own and safe test profiles.
Authenticate with least privilege
For a private integration, use a private API key with only the scopes required by the endpoints. Creating events currently requires events:write.
Security controls:
- store the key in a secret manager;
- do not expose a private key in browser or mobile code;
- use separate credentials by environment and integration;
- restrict access to deployment identities;
- rotate and revoke keys through a documented process;
- do not log authorization headers;
- alert on unexpected usage.
For a product integration used by many Klaviyo accounts, Klaviyo's authentication guide recommends OAuth for tech partners and lists improved rate limits among its benefits. In our reading, that is a better fit than asking every customer to paste a private key.
Server-side API or Klaviyo.js
Klaviyo's authentication guide separates two families. Server-side /api endpoints use a private key (prefix pk_, sent as Authorization: Klaviyo-API-Key your-private-api-key) and should be handled on your server. Client-side /client endpoints use the public key, your 6-character company ID (also called site ID), which cannot access secure data in your account. To manage keys, you need an Owner, Admin or Manager role (Settings, then API keys).
Klaviyo's JavaScript API exposes klaviyo.identify (set properties on a person, with an email or, for SMS-only contacts, a phone number) and klaviyo.track (record an event for an identified user). In our reading, browser events such as Viewed Product fit Klaviyo.js, while events produced by your backend (order confirmation, plan change) fit the server-side API. If the same action is sent from both, define which one owns the event: the browser event and the server event are separate unless they share profile, metric and unique_id.
Pin an API revision
Klaviyo versions modern APIs with date-based revision headers. Pass a supported revision such as the exact date selected from the current reference. Do not copy the example date in this article as a permanent value.
Pinning provides predictable request and response behavior. Maintain:
- current pinned revision;
- reference and changelog links;
- upgrade owner;
- contract tests against the next revision;
- deprecation review cadence.
Klaviyo's versioning policy marks beta revisions with a .pre suffix and says they should not be used in production. Use stable revisions for customer-facing systems.
Structure the Create Event request
The request body nests data, type and attributes, as in the examples of the Events API overview. Conceptually, send:
{
"data": {
"type": "event",
"attributes": {
"metric": {
"data": {
"type": "metric",
"attributes": { "name": "Project Published" }
}
},
"profile": {
"data": {
"type": "profile",
"attributes": { "email": "qa@your-owned-domain.com" }
}
},
"properties": {
"project_id": "prj_123",
"workspace_id": "ws_456",
"template": "weekly-report"
},
"time": "2026-07-16T09:30:00Z",
"unique_id": "90974d0d-5d62-4d78-98ee-450d74cd7090"
}
}
}
Use the exact current API reference and SDK types because shape and supported fields can evolve.
Use unique_id for idempotency
Klaviyo currently deduplicates events using profile, metric, and unique_id. Generate a stable unique identifier for each logical source event and reuse the same value on every retry.
Good source IDs:
- immutable order or transaction event ID;
- message ID from an event bus;
- UUID stored with the source record;
- deterministic ID from a truly unique business occurrence.
Do not generate a new UUID on every retry because that defeats idempotency. Do not reuse an order ID across multiple different order events without including event type or source occurrence.
The current documentation warns that, without unique_id, events for the same profile and metric in the same second can collide because the default is derived from the timestamp. Provide it for production event sources.
Send the actual occurrence time
Set time to when the source action occurred, not when a retry worker delivered it. This keeps event history and time-based analysis accurate.
Use an ISO 8601 timestamp with an explicit time zone, commonly UTC, as in Klaviyo's examples (+00:00). The rate-limit guide lists event timestamps between 1990 and "now" plus one year as the accepted range, so validate impossible dates and stale source clocks.
For delayed events, decide whether the lifecycle should still trigger. A payment failure delivered six hours late may need different handling. Event timestamp accuracy does not automatically prevent a flow from acting on stale data, so use eligibility filters or freshness properties.
Keep properties useful and bounded
Event properties should support flow content, segmentation, debugging, and analysis. Examples:
- stable object IDs;
- product or plan name;
- amount and currency;
- reason code with controlled values;
- destination URL built safely;
- market or locale;
- event schema version.
Avoid sending full internal objects, large HTML, secrets, payment data, or unused personal information. Klaviyo's rate-limit guide lists 400 event properties per data packet, 100 kB per field, 4,000 items per array and 11 levels of nested objects. Values of 0, null and an empty string are ignored when setting event properties, so they cannot be used for segmentation. Treat the current API reference as the authority.
Use controlled property names and types. A property that is sometimes number and sometimes string makes segmentation unreliable.
Place only truly non-segmentable large context into fields designed for that purpose, and still minimize it. Customer messaging systems are not data lakes.
Treat 202 as queued, not fully processed
The Create Event endpoint currently responds 202 Accepted after validation and submission for processing. Klaviyo explicitly says that success does not guarantee processing is complete.
Your producer should record:
- source event ID;
- request time and attempt;
- endpoint revision;
- response status;
- final retry or dead-letter state;
- a correlation value that does not expose personal data.
Klaviyo's troubleshooting section says events are created asynchronously and can take up to a few minutes to appear in the interface or in the Get Events API. For critical integrations, reconcile source events with Klaviyo event retrieval or profile activity samples, taking that latency into account. Do not perform a read immediately and declare failure when the pipeline is asynchronous.
Handle errors and rate limits
Classify responses:
- 2xx: accepted according to endpoint semantics;
- 400: a required parameter is missing or a parameter is invalid, so fix the payload and do not retry blindly;
- 401 or 403: missing authentication information, or valid credentials without the required permission (scope);
- 404: the requested resource does not exist;
- 429: rate limit, honor
Retry-After; - 5xx and network timeout: retry with bounded exponential backoff and jitter.
Klaviyo uses a burst window (1 second) and a steady window (1 minute), with endpoint-specific limits published in the reference. At the time of review, the Create Event page shows burst 350/s and steady 3,500/m. Non-429 responses carry rate-limit headers, and a 429 replaces them with a Retry-After header. The guide adds that immediate retries always receive a 429.
Klaviyo recommends watching for 429 and 503 and retrying with an exponential backoff that includes some randomness. Retry only after the Retry-After delay has expired. In our reading, a queue, concurrency control and a dead-letter path complete that approach. Keep the same unique_id through retries.
Alert on sustained error rate, dead-letter depth, delivery latency, and unknown validation errors.
Use bulk endpoints for appropriate volume
When backfilling or sending high event volume, review the Bulk Create Events reference (POST /api/event-bulk-create-jobs). At the time of review it accepts up to 1,000 events and 5 MB per request, with burst 10/s and steady 150/m. Retain individual source IDs: repeated unique_id values inside one bulk request return a 400 and none of the events in that request are processed.
Do not use live flow-triggering events for a historical replay without a lifecycle plan. Klaviyo warns that replaying past events can re-fire flows and send messages to profiles who already received them.
Use backfill: true for historical replay
Klaviyo's current Events API supports a backfill boolean for historical data. With backfill: true, the event remains available in event data and segmentation but does not trigger flows.
Use it when:
- migrating historical orders;
- replaying corrected past events;
- rebuilding data after an integration gap where customer messages should not fire;
- importing CRM history for analytics.
Use time and stable unique_id as well. Test backfill in a safe account or profile before a large import. Confirm downstream reporting and segmentation behavior matches the current documentation.
If some missed events should trigger a customer action, do not remove backfill protection globally. Create an explicit recovery audience and communication plan with freshness, consent, and customer relevance checks.
Outgoing webhooks from a flow
Sending events to Klaviyo and receiving data from Klaviyo are two different mechanisms. Klaviyo's flow webhook guide describes the webhook action: when a profile reaches that action in a flow, Klaviyo sends a POST request to the URL you configure, with the payload you wrote. The developer guide adds the conditions:
- the URL must be valid, start with
https://, have no self-signed certificate and not redirect; - the body is JSON only, and headers can carry an authentication value;
- only POST is supported, and Klaviyo says not to use webhooks to subscribe profiles to lists;
- the triggers are those that can start a flow (for example
Started Checkout,Placed Order,Subscribed to List,Added to a Segment); - a 2xx response counts as success, retryable errors are retried with exponential backoff and then move to a failed queue, and each request carries an
X-Klaviyo-Flow-IDheader; - two-step authentication is required, and only Manager, Admin or Owner roles can add or edit webhooks.
A flow webhook is not a two-way sync: it does not bring data from your system back into Klaviyo. For that, use the Events API described above.
Design flow safety around events
An API event should not have unrestricted power to send.
Add flow controls:
- trigger filters for valid event properties;
- profile and channel eligibility;
- event freshness where relevant;
- current-state filter before delayed messages;
- cancellation or success exit;
- frequency and re-entry rules;
- fallback for missing content;
- internal notification on suspicious payload;
- manual mode during initial validation.
Use a synthetic or controlled event to test every branch. Then run a small production cohort before broad live status.
Monitoring and reconciliation
Create dashboards for:
- source events created;
- accepted requests;
- response codes by class;
- retry and dead-letter volume;
- end-to-end latency;
- Klaviyo metric volume;
- missing or unknown property rate;
- distinct profiles;
- flow entries and exits;
- downstream delivery and conversion.
Compare by hour and day with expected seasonality. Alert on both drop and spike. A tenfold event increase can be a duplicate bug even if every API response is successful.
Maintain a runbook with key rotation, revision upgrade, replay procedure, flow pause, event source owner, and incident contacts.
Implementation test plan
- Valid event for an existing controlled profile.
- Valid event that creates or updates a permitted profile attribute, if used.
- Duplicate retry with the same
unique_id. - Two legitimate events in the same second with different IDs.
- Missing required property.
- Wrong type and unknown enum value.
- Network timeout followed by safe retry.
- Simulated or controlled 429 handling.
- Historical event with
backfill: true. - Profile unsubscribed or suppressed for the target channel.
- Conversion or cancellation during a flow delay.
- Event volume spike and alert.
Verify the event in Klaviyo, flow behavior, message preview, logs, and downstream reports. Do not use only the HTTP response as QA evidence.
FAQ
What endpoint creates a Klaviyo event?
The current endpoint is POST https://a.klaviyo.com/api/events. Use the official current reference, required authentication, supported revision, and the payload structure shown there.
Why did I receive 202 but not see the event?
202 means accepted for asynchronous processing, not guaranteed complete. Allow processing time, verify identity and payload, check test-domain restrictions, deduplication, logs, and the current status page.
How do I prevent duplicate Klaviyo events?
Provide a stable unique_id per logical event and reuse it on retries. Klaviyo currently deduplicates by profile, metric, and unique ID.
How should I import historical events?
Provide the original time, stable IDs, and use backfill: true when the replay must not trigger flows. Test a small batch and reconcile counts.
How should 429 errors be retried?
Honor Retry-After, queue requests, and use bounded backoff with jitter. Respect the endpoint's burst and steady limits and preserve idempotency.
Make custom events dependable enough to trigger customers
Deliver defines event contracts, implements reliable ingestion, and validates lifecycle behavior from source system to message. Request a Klaviyo Events API implementation review.
Provenance and verification
Check of 2026-11-03, pages reopened as raw HTML converted to text and read. Create Event reference (endpoint, burst 350/s and steady 3500/m, events:write scope, 202 meaning, revision header). Events API overview (unique_id idempotency, deduplication on profile, metric and unique_id, backfill, test-domain drop, 400 event properties, 1,000 events and 5 MB for bulk, 'up to a few minutes' for 202). Rate-limit guide (burst and steady windows, Retry-After, status codes, event limits table). Versioning policy (.pre beta revisions). Authentication guide (pk_ private keys, 6-character public key, OAuth). JavaScript API guide (identify and track). Flow webhook help article and developer guide (POST only, HTTPS URL, JSON body, flow-trigger events, MFA, retries, X-Klaviyo-Flow-ID).
- Sources checked on
- Reviewed by
- Claude (AI review, Klaviyo developer documentation reopened and read on 2026-11-03)
- AI assistance
- Yes
- Sources
-
- developers.klaviyo.com/en/reference/create_event
- developers.klaviyo.com/en/reference/events_api_overview
- developers.klaviyo.com/en/reference/bulk_create_events
- developers.klaviyo.com/en/docs/rate_limits_and_error_handling
- developers.klaviyo.com/en/docs/api_versioning_and_deprecation_policy
- developers.klaviyo.com/en/docs/authenticate_
- developers.klaviyo.com/en/docs/javascript_api
- help.klaviyo.com/hc/en-us/articles/4534329515931
- developers.klaviyo.com/en/docs/how_to_add_a_webhook_action_to_a_flow
Want to apply this to your stack?
Spend 30 minutes with Charlotte to review your CRM setup, size the opportunity and leave with a practical action plan.
Book a 30-minute call →