Klaviyo is a marketing automation platform, used extensively by eCommerce brands to send email, SMS and push notifications to customers and ultimately drive increased revenue for retailers. If you’re looking to integrate with Klaviyo, their API is extensive and fairly complex (by nature of their product / platform) but the API is well-documented with plenty of developer friendly features and guides. In this blog I’ll explore some of the key considerations for integrating with Klaviyo as well as some tips and tricks that I’ve learned while building integrations with Klaviyo.
Before we look at how to integrate with Klayviyo, let’s take a quick look at just some of the use cases for integrating with Klaviyo.
Klaviyo supports both API key and OAuth authentication. API key authentication is best for quickly getting spun up and testing endpoints or for an internal integration that won’t be installed by end-users. A private API key can be generated from Klaviyo account settings and then should be passed with API requests in the headers:
Authorization: 'Klaviyo-API-Key [private API key]'
Most integrations should use OAuth authentication, which provides increased security, improved user-access management, and the eligibility to be listed in Klaviyo’s Integration Directory. Using OAuth also enables higher volume integrations since each access token is rate-limited separately, whereas all uses of an API key are rate-limited together. To get started with OAuth, create an OAuth app by going to Integrations > Developers > Manage Apps > Create App in your Klaviyo account. Configure the app with a name, scopes, and redirect URLs. Take note of the Client ID and Secret, which will be used during the OAuth flow to get an access token for each user that installs the app.
Klaviyo requires the use of PKCE for additional security when generating an access token. Prior to making the authorization request for a user, generate a code_verifier
– a random string with a length between 43 and 128 characters that is unique for every authorization request. For example, you could seed a random number generator with the current timestamp and an identifying piece of information about the user being authenticated, and then use that to generate a string of 50 random numbers. Next, create the code_challenge
, which is the base 64 url-safe encoded string of the SHA-256 hash of the code_verifier
. Store the code_verifier
in a database or cache as you’ll need to include it when exchanging the code for an access token. In the query params of the authorization request, include the code_challenge
and code_challenge_method = S256
. Then, when processing the callback from the authorization request, use the identifying information included in the state param to lookup the correct code_verifier
and then include the code_verifier
in the request body to exchange the code for an access token.
Once the access token is retrieved, authenticate requests with the header
Authorization: 'Bearer [access token]'
Access tokens are valid for 1 hour (but, if you rely on this, be sure to check the expires_in
value returned with the token in case the lifespan changes). You can certainly refresh the token before it expires, and existing access tokens remain valid when new ones are created. However, note that the refresh token endpoint has a rate limit of 10 calls per minute so it is ill-advised to refresh the access token prior to every time it is used, since that would effectively limit you to 10 calls per minute across all endpoints. Lastly, be aware that refresh tokens are invalidated if not used for 90 days.
Klaviyo API versioning is handled by specifying a revision in the headers, such as
revision: '2024-10-15'
A revision represents a snapshot of the API on a certain date. The provided revision must match one of the released API versions; for example, the current date cannot be supplied with the expectation that this will fall back to the most recent API version. Breaking changes are released in new revisions, while existing revisions may be updated with non-breaking changes. The suggested practice is to pin the integration to the most recent, stable revision at the time of development, and then every 12 to 18 months update the pinned revision version and make all necessary changes to the integration to comply with the updated API at that time. API revisions have a lifespan of 2 years; for example, the revision ‘2024-10-15’ was released on October 15, 2024, will be deprecated on October 15, 2025, and will no longer be supported on October 15, 2026. API calls made with a specified revision that is no longer supported will fall back to the oldest supported revision, but this could introduce unexpected behavior.
The Klaviyo API adheres to the JSON:API specification, which provides a standard for easily filtering and sorting API results, and for efficiently fetching related resources. When adding a Klaviyo API call to your integration, consider if using one or multiple of these features would make the operation more efficient. For example, use the filter param to just fetch a single profile with a specific email address instead of fetching all profiles and filtering in the integration. Or, use the sort param to retrieve paginated results in the desired order so that you can process them sequentially – perhaps with an async generator.
Use the filter query param with a variety of comparison operators to limit the response from an API request to only the resources you are interested in. For example, fetch only profiles with a certain email address
GET /api/profiles?filter=equals(email,”
test@test.com
”)
Or fetch only lists created since a certain date
GET /api/lists?filter=greater_than(created,2025-01-01T00:00:00Z)
Use the sort query param with supported endpoints to retrieve results in your desired order. For example, sort profiles by their last updated date
GET /api/profiles?sort=updated
This will return results in ascending (oldest to newest) order. To sort in descending order, append a “-” to the beginning of the sort field, like ?sort=-updated
.
Use the include query param to fetch related resources. This is a powerful tool to reduce the number of API requests you need to make. For example, to fetch events with associated profiles
GET /api/events?include=profile
And multiple resources can be chained together by specifying them in a comma separated list, like ?include=profile,metric
.
When designing your integration, it’s important to consider how a sync will be triggered. Common integration triggers include:
Klaviyo offers two types of webhooks: flow webhooks and system webhooks. Flow webhooks are a special type of webhook that can be fired when a Klaviyo Flow reaches a certain step. System webhooks are the standard webhook type; they are fired when a particular event in Klaviyo has occurred, for example when an email is clicked or a notification is received. To take advantage of system webhooks you’ll need to subscribe to Klaviyo’s Customer Data Platform (CDP) and then you can configure them via the API when setting up the integration or when adding a new user to the integration.
If you need assistance with a Klaviyo integration project, or just don’t want to deal with it yourself, reach out to us at Pandium. Our team has the experience and knowledge developing complex, native integrations across a variety of systems, and we can help you get the most out of your Klaviyo integration.