Skip to content

Latest commit

 

History

History
2010 lines (1011 loc) · 44.6 KB

File metadata and controls

2010 lines (1011 loc) · 44.6 KB

Klaviyo JavaScript SDK

  • SDK version: 5.0.0

  • Revision: 2023-07-15

Helpful Resources

Design & Approach

This SDK is a thin wrapper around our API. See our API Reference for full documentation on API behavior.

This SDK exactly mirrors the organization and naming convention of the above language-agnostic resources, with a few namespace changes to make it Pythonic (details in Appendix).

Organization

This SDK is organized into the following resources:

  • Accounts
  • Campaigns
  • Catalogs
  • DataPrivacy
  • Events
  • Flows
  • Lists
  • Metrics
  • Profiles
  • Segments
  • Tags
  • Templates

Installation

NPM

You can install this library using npm.

npm install klaviyo-api

source code

Alternatively, you can also run this using this repo as source code, by running one of the following shell commands within the cloned repo:

npm install

and then running JavaScript from the cloned repo.

Usage Example

To instantiate the ConfigWrapper

import {ConfigWrapper} from 'klaviyo-api'

ConfigWrapper("KLAVIYO PRIVATE KEY GOES HERE")

Or if ES6 isn't your thing

var klaviyoSdk = require('klaviyo-api');

klaviyoSdk.ConfigWrapper("KLAVIYO PRIVATE KEY GOES HERE")

To edit the exponential backoff built into the ConfigWrapper you can pass optional parameters

import {ConfigWrapper} from 'klaviyo-api'

ConfigWrapper("KLAVIYO PRIVATE KEY GOES HERE", {
    numOfAttempts: 5, // max number of rety attempts. Default is 3
    timeMultiple: 10, // how exponental the timing is. Default is 5
    startingDelay: 1000, // How long before first retry. Default is 500
})

NOTES:

  • The SDK retries on resolvable errors, namely: rate limits (common) and server errors on klaviyo (rare).
  • The first ConfigWrapper created is the default, if you want to use more than one api key see multi-store instructions below

To call the getProfile operation:

import {Profiles} from 'klaviyo-api';

const profileId = "PROFILE_ID";
const opts = {};

Profiles.getProfile(profileId, opts)
    .then(data => 'Do Something Here')
    .catch(error => 'An error was thrown check the HTTP code with error.status');

or if you want to use async await

import {Profiles} from 'klaviyo-api';

const profileId = "PROFILE_ID";
const opts = {};

// Just make sure you are calling with the async tag ie. async () => {}
try {
    response = await Profiles.getProfile(profileId, opts)
    console.log(response);
} catch (e) {
    console.log(e);
}

once again if you're not using ES6

var KlaviyoSdk = require('klaviyo-api');

var profileId = "PROFILE_ID";
var opts = {};

KlaviyoSdk.Profiles.getProfile(profileId, opts)
    .then(data => 'Do Something Here')
    .catch(error => 'An error was thrown check the HTTP code with error.status');

What the response looks like

The response is an object with three parts: status, headers, and body

import {Profiles} from 'klaviyo-api';

const opts = {};

// how to get your request information
try {
    response = await Profiles.getProfiles(opts)
    const response_body = response.body
    // first index id
    const id = response_body.data[0].id
    // getting the next page cursor
    const next_page_cursor = response_body.links.next
    // rest of the response information
    const status = response.status
    const headers = response.headers
} catch (e) {
    console.log(e);
}

Multiple stores

if you need to use multiple api keys, you can forgo the wrapped api classes and make you own

import {ConfigWrapper, CatalogsApi} from 'klaviyo-api'

const catalogApi = new CatalogsApi(ConfigWrapper("KLAVIYO PRIVATE KEY GOES HERE"))
const r = await catalogApi.createCatalogCategory(body)

Optional Parameters and Json Api Features

Here we will go over

  • Pagination
  • Page size
  • Additional Fields
  • Filtering
  • Sparse Fields
  • Sorting
  • Relationships

Quick rule

As a reminder, the optional parameters are named slightly differently from how you would make the call without the SDK docs, query parameter names have variables that make bad JavaScript names like page[cursor] are transformed to pageCursor. (Remove the weird characters and append words with camelCase). A modern IDE will make the positional arguments look a bit more clear.

Cursor based Pagination

All the endpoints that return a list of results use cursor-based pagination.

Obtain the cursor value from the call you want to get the next page for, then pass it under the pageCursor optional parameter. The page cursor looks like WzE2NDA5OTUyMDAsICIzYzRjeXdGTndadyIsIHRydWVd.

API call:

https://a.klaviyo.com/api/profiles/?page[cursor]=WzE2NTcyMTM4NjQsICIzc042NjRyeHo0ciIsIHRydWVd

SDK call:

import { ConfigWrapper, ProfilesApi } from 'klaviyo-api'
const profilesApi = new ProfilesApi(ConfigWrapper("<Your Private Key Here>"))

const profileList = await profilesApi.getProfiles({pageCursor: 'WzE2NTcyMTM4NjQsICIzc042NjRyeHo0ciIsIHRydWVd'})

You get the cursor for the next page from body.link.next which returns the entire URL of the next call but the sdk will accept the entire link and use only the relevant cursor.

Here is an example of getting the second next and passing in the page cursor:

import { ConfigWrapper, ProfilesApi } from 'klaviyo-api'
const profilesApi = new ProfilesApi(ConfigWrapper("<Your Private Key Here>"))

try {
    const profilesListFirstPage = await profilesApi.getProfiles()
    const nextPage = profilesList.body.links.next
    const profileListSecondPage = await profilesApi.getProfiles({pageCursor: nextPage})
    console.log(profileListSecondPage.body)
} catch (e) {
    console.log(e)
}

There are more page cursors than just next, check the endpoint's docs or the response type, but often there is first, last, next and prev.

Page Size

Some endpoint you can get a larger or smaller page size by using the pageSize parameter.

API call:

https://a.klaviyo.com/api/profiles/?page[size]=20

SDK call:

import { ConfigWrapper, ProfilesApi } from 'klaviyo-api'
const profilesApi = new ProfilesApi(ConfigWrapper("<Your Private Key Here>"))

const profileList = await profilesApi.getProfiles({pageSize: 20})

Additional Fields

Additional fields are used to populate part of the response that would be null otherwise. For the getProfile endpoint you can pass in a request to get the predictive analytics of the profile. Using the additionalFields parameter often will change the rate limit of the endpoint so be sure to keep an eye on your usage.

API call

https://a.klaviyo.com/api/profiles/01GDDKASAP8TKDDA2GRZDSVP4H/?additional-fields[profile]=predictive_analytics

SDK call:

import { ConfigWrapper, ProfilesApi } from 'klaviyo-api'
const profilesApi = new ProfilesApi(ConfigWrapper("<Your Private Key Here>"))

const profileId = '01GDDKASAP8TKDDA2GRZDSVP4H'
const profile = await profilesApi.getProfile(profileId, {additionalFieldsProfile: ['predictive_analytics']})

// If your profile has enough information for predictive analytis it will populate
console.log(profile.body.data.attributes.predictiveAnalytics)

Filtering

Filter by passing the filter as a string as under the optional parameter filter. Note that when filtering by a property it will be snake_case instead of camelCase, ie. metric_id

Read more about formatting your filter strings in our developer documentation

Here is an example of a filter string for results between two date times: less-than(updated,2023-04-26T00:00:00Z),greater-than(updated,2023-04-19T00:00:00Z)

Here is a code example filter for profiles with the matching emails:

https://a.klaviyo.com/api/profiles/?filter=any(email,["[email protected]","[email protected]"]

SDK call:

import { ConfigWrapper, ProfilesApi } from 'klaviyo-api'
const profilesApi = new ProfilesApi(ConfigWrapper("<Your Private Key Here>"))

const filter = 'any(email,["[email protected]","[email protected]"])'
// remember { filter: filter } is the same as {filter}
const profileList = await profilesApi.getProfiles({filter})

Sparse Fields

If you only want a specific subset of data from a specific query you can use sparse fields to request only the specific properties. The SDK expands the optional sparse fields into their own option, where you can pass a list of the desired items to include.

To get a list of event properties the API call you would use is:

https://a.klaviyo.com/api/events/?fields[event]=event_properties

SDK call:

import { ConfigWrapper, EventsApi } from 'klaviyo-api'
const eventsApi = new EventsApi(ConfigWrapper("<Your Private Key Here>"))

const eventsList = await eventsApi.getEvents({fieldsEvent: ["event_properties"]})

Sorting

Your can request the results of specific endpoints to be ordered by a given parameter. The direction of the sort can swapped by adding a - in front of the sort key. For example datetime will be ascending while -datetime will be descending.

If you are unsure about the available sort fields you can always check the documentation for the endpoint you are using. For a comprehensive list that links to the documentation for each function check the Endpoints section below.

API Call to get events sorted by oldest to newest datetime:

https://a.klaviyo.com/api/events/?sort=-datetime

SDK call:

import { ConfigWrapper, EventsApi } from 'klaviyo-api'
const eventsApi = new EventsApi(ConfigWrapper("<Your Private Key Here>"))

const events = await eventsApi.getEvents({sort: '-datetime'})

Includes

You can add additional information to your API response via additional fields and the includes parameter. This allows you to get information about two or more objects from a single API call. Using the includes parameter often changes the rate limit of the endpoint so be sure to take note.

API call to get profile information and the information about the lists the profile is in:

https://a.klaviyo.com/api/profiles/01GDDKASAP8TKDDA2GRZDSVP4H/?include=lists

SDK call:

import { ConfigWrapper, ProfilesApi } from 'klaviyo-api'
const profilesApi = new ProfilesApi(ConfigWrapper("<Your Private Key Here>"))

const profileId = '01GDDKASAP8TKDDA2GRZDSVP4H'
const profile = await profilesApi.getProfile(profileId, {include:["lists"]})

// Profile information is accessed the same way with
console.log(profile.body.data)
// Lists related to the profile with be accessible via the included array
console.log(profile.body.included)

Note about sparse fields and relationships: you can request only specific fields of the included object as well.

import { ConfigWrapper, ProfilesApi } from 'klaviyo-api'
const profilesApi = new ProfilesApi(ConfigWrapper("<Your Private Key Here>"))

const profileId = '01GDDKASAP8TKDDA2GRZDSVP4H'
// Use the fieldsLists property to request only the list name
const profile = await profilesApi.getProfile(profileId, { fieldsList: ['name'], include: ["lists"])

// Profile information is accessed the same way with
console.log(profile.body.data)
// Lists related to the profile with be accessible via the included array
console.log(profile.body.included)

Relationships

The Klaviyo API has a series of endpoints to expose the relationships between different Klaviyo Items. You can read more about relationships inour documentation.

Here are some use cases and their examples:

API call to get the list membership for a profile with the given profile ID:

https://a.klaviyo.com/api/profiles/01GDDKASAP8TKDDA2GRZDSVP4H/relationships/lists/

SDK call:

import { ConfigWrapper, ProfilesApi } from 'klaviyo-api'
const profilesApi = new ProfilesApi(ConfigWrapper("<Your Private Key Here>"))

const profileId = '01GDDKASAP8TKDDA2GRZDSVP4H'
const profileRelationships = await profilesApi.getProfileRelationshipsLists(profileId)

For another example:

Get all campaigns associated with the given tag_id.

API call:

https://a.klaviyo.com/api/tags/9c8db7a0-5ab5-4e3c-9a37-a3224fd14382/relationships/campaigns/

SDK call:

import { ConfigWrapper, TagsApi } from 'klaviyo-api'
const tagsApi = new TagsApi(ConfigWrapper("< Your private key here >"))

const tagId = '9c8db7a0-5ab5-4e3c-9a37-a3224fd14382'
const relatedCampagins = tagsApi.getTagRelationshipsCampaigns(tagId)

Combining

You can use any combination of the features outlines above in conjunction with one another.

API call to get events associated with a specific metric, then return just the event properties sorted by oldest to newest datetime:

https://a.klaviyo.com/api/events/?fields[event]=event_properties&filter=equals(metric_id,"URDbLg")&sort=-datetime

SDK call:

import { ConfigWrapper, EventsApi } from 'klaviyo-api'
const eventsApi = new EventsApi(ConfigWrapper("<Your Private Key Here>"))

const metricId = 'URDbLg'
const filter = `equal(metric_id,"${metricId}")`
const events = await eventsApi.getEvents({ fieldsEvent: ['event_properties'], filter, sort: '-datetime'})

Comprehensive list of Operations & Parameters

NOTE:

  • Organization: Resource groups and operation_ids are listed in alphabetical order, first by Resource name, then by OpenAPI Summary. Operation summaries are those listed in the right side bar of the API Reference.
  • For example values / data types, as well as whether parameters are required/optional, please reference the corresponding API Reference link.
  • Some args are required for the API call to succeed, the API docs above are the source of truth regarding which params are required.

AccountsApi

const Accounts.getAccount(id, opts)
const Accounts.getAccounts(opts)

CampaignsApi

const Campaigns.createCampaign(body)
const Campaigns.createCampaignClone(body)
const Campaigns.createCampaignMessageAssignTemplate(body)
const Campaigns.createCampaignRecipientEstimationJob(body)
const Campaigns.createCampaignSendJob(body)
const Campaigns.deleteCampaign(id)
const Campaigns.getCampaign(id, opts)
const Campaigns.getCampaignCampaignMessages(id, opts)
const Campaigns.getCampaignMessage(id, opts)
const Campaigns.getCampaignMessageCampaign(id, opts)
const Campaigns.getCampaignMessageRelationshipsCampaign(id)
const Campaigns.getCampaignMessageRelationshipsTemplate(id)
const Campaigns.getCampaignMessageTemplate(id, opts)
const Campaigns.getCampaignRecipientEstimation(id, opts)
const Campaigns.getCampaignRecipientEstimationJob(id, opts)
const Campaigns.getCampaignRelationshipsCampaignMessages(id)
const Campaigns.getCampaignRelationshipsTags(id)
const Campaigns.getCampaignSendJob(id, opts)
const Campaigns.getCampaignTags(id, opts)
const Campaigns.getCampaigns(filter, opts)
const Campaigns.updateCampaign(body, id)
const Campaigns.updateCampaignMessage(body, id)
const Campaigns.updateCampaignSendJob(body, id)

CatalogsApi

const Catalogs.createBackInStockSubscription(body)
const Catalogs.createCatalogCategory(body)
const Catalogs.createCatalogCategoryRelationshipsItems(body, id)
const Catalogs.createCatalogItem(body)
const Catalogs.createCatalogItemRelationshipsCategories(body, id)
const Catalogs.createCatalogVariant(body)
const Catalogs.deleteCatalogCategory(id)
const Catalogs.deleteCatalogCategoryRelationshipsItems(body, id)
const Catalogs.deleteCatalogItem(id)
const Catalogs.deleteCatalogItemRelationshipsCategories(body, id)
const Catalogs.deleteCatalogVariant(id)
const Catalogs.getCatalogCategories(opts)
const Catalogs.getCatalogCategory(id, opts)
const Catalogs.getCatalogCategoryItems(id, opts)
const Catalogs.getCatalogCategoryRelationshipsItems(id, opts)
const Catalogs.getCatalogItem(id, opts)
const Catalogs.getCatalogItemCategories(id, opts)
const Catalogs.getCatalogItemRelationshipsCategories(id, opts)
const Catalogs.getCatalogItemVariants(id, opts)
const Catalogs.getCatalogItems(opts)
const Catalogs.getCatalogVariant(id, opts)
const Catalogs.getCatalogVariants(opts)
const Catalogs.getCreateCategoriesJob(jobId, opts)
const Catalogs.getCreateCategoriesJobs(opts)
const Catalogs.getCreateItemsJob(jobId, opts)
const Catalogs.getCreateItemsJobs(opts)
const Catalogs.getCreateVariantsJob(jobId, opts)
const Catalogs.getCreateVariantsJobs(opts)
const Catalogs.getDeleteCategoriesJob(jobId, opts)
const Catalogs.getDeleteCategoriesJobs(opts)
const Catalogs.getDeleteItemsJob(jobId, opts)
const Catalogs.getDeleteItemsJobs(opts)
const Catalogs.getDeleteVariantsJob(jobId, opts)
const Catalogs.getDeleteVariantsJobs(opts)
const Catalogs.getUpdateCategoriesJob(jobId, opts)
const Catalogs.getUpdateCategoriesJobs(opts)
const Catalogs.getUpdateItemsJob(jobId, opts)
const Catalogs.getUpdateItemsJobs(opts)
const Catalogs.getUpdateVariantsJob(jobId, opts)
const Catalogs.getUpdateVariantsJobs(opts)
const Catalogs.spawnCreateCategoriesJob(body)
const Catalogs.spawnCreateItemsJob(body)
const Catalogs.spawnCreateVariantsJob(body)
const Catalogs.spawnDeleteCategoriesJob(body)
const Catalogs.spawnDeleteItemsJob(body)
const Catalogs.spawnDeleteVariantsJob(body)
const Catalogs.spawnUpdateCategoriesJob(body)
const Catalogs.spawnUpdateItemsJob(body)
const Catalogs.spawnUpdateVariantsJob(body)
const Catalogs.updateCatalogCategory(body, id)
const Catalogs.updateCatalogCategoryRelationshipsItems(body, id)
const Catalogs.updateCatalogItem(body, id)
const Catalogs.updateCatalogItemRelationshipsCategories(body, id)
const Catalogs.updateCatalogVariant(body, id)

DataPrivacyApi

const DataPrivacy.requestProfileDeletion(body)

EventsApi

const Events.createEvent(body)
const Events.getEvent(id, opts)
const Events.getEventMetric(id, opts)
const Events.getEventProfile(id, opts)
const Events.getEventRelationshipsMetric(id)
const Events.getEventRelationshipsProfile(id)
const Events.getEvents(opts)

FlowsApi

const Flows.getFlow(id, opts)
const Flows.getFlowAction(id, opts)
const Flows.getFlowActionFlow(id, opts)
const Flows.getFlowActionMessages(id, opts)
const Flows.getFlowActionRelationshipsFlow(id)
const Flows.getFlowActionRelationshipsMessages(id, opts)
const Flows.getFlowFlowActions(id, opts)
const Flows.getFlowMessage(id, opts)
const Flows.getFlowMessageAction(id, opts)
const Flows.getFlowMessageRelationshipsAction(id)
const Flows.getFlowRelationshipsFlowActions(id, opts)
const Flows.getFlowRelationshipsTags(id)
const Flows.getFlowTags(id, opts)
const Flows.getFlows(opts)
const Flows.updateFlow(body, id)

ListsApi

const Lists.createList(body)
const Lists.createListRelationships(body, id)
const Lists.deleteList(id)
const Lists.deleteListRelationships(body, id)
const Lists.getList(id, opts)
const Lists.getListProfiles(id, opts)
const Lists.getListRelationshipsProfiles(id, opts)
const Lists.getListRelationshipsTags(id)
const Lists.getListTags(id, opts)
const Lists.getLists(opts)
const Lists.updateList(body, id)

MetricsApi

const Metrics.getMetric(id, opts)
const Metrics.getMetrics(opts)
const Metrics.queryMetricAggregates(body)

ProfilesApi

const Profiles.createProfile(body)
const Profiles.getProfile(id, opts)
const Profiles.getProfileLists(id, opts)
const Profiles.getProfileRelationshipsLists(id)
const Profiles.getProfileRelationshipsSegments(id)
const Profiles.getProfileSegments(id, opts)
const Profiles.getProfiles(opts)
const Profiles.subscribeProfiles(body)
const Profiles.suppressProfiles(body)
const Profiles.unsubscribeProfiles(body)
const Profiles.unsuppressProfiles(body)
const Profiles.updateProfile(body, id)

SegmentsApi

const Segments.getSegment(id, opts)
const Segments.getSegmentProfiles(id, opts)
const Segments.getSegmentRelationshipsProfiles(id, opts)
const Segments.getSegmentRelationshipsTags(id)
const Segments.getSegmentTags(id, opts)
const Segments.getSegments(opts)
const Segments.updateSegment(body, id)

TagsApi

const Tags.createTag(body)
const Tags.createTagGroup(body)
const Tags.createTagRelationshipsCampaigns(body, id)
const Tags.createTagRelationshipsFlows(body, id)
const Tags.createTagRelationshipsLists(body, id)
const Tags.createTagRelationshipsSegments(body, id)
const Tags.deleteTag(id)
const Tags.deleteTagGroup(id)
const Tags.deleteTagRelationshipsCampaigns(body, id)
const Tags.deleteTagRelationshipsFlows(body, id)
const Tags.deleteTagRelationshipsLists(body, id)
const Tags.deleteTagRelationshipsSegments(body, id)
const Tags.getTag(id, opts)
const Tags.getTagGroup(id, opts)
const Tags.getTagGroupRelationshipsTags(id)
const Tags.getTagGroupTags(id, opts)
const Tags.getTagGroups(opts)
const Tags.getTagRelationshipsCampaigns(id)
const Tags.getTagRelationshipsFlows(id)
const Tags.getTagRelationshipsLists(id)
const Tags.getTagRelationshipsSegments(id)
const Tags.getTagRelationshipsTagGroup(id)
const Tags.getTagTagGroup(id, opts)
const Tags.getTags(opts)
const Tags.updateTag(body, id)
const Tags.updateTagGroup(body, id)

TemplatesApi

const Templates.createTemplate(body)
const Templates.createTemplateClone(body)
const Templates.createTemplateRender(body)
const Templates.deleteTemplate(id)
const Templates.getTemplate(id, opts)
const Templates.getTemplates(opts)
const Templates.updateTemplate(body, id)

Appendix

Limitations

  • The api_key is set at the global level: this means that if you manage multiple stores, you will need to run the code for each store in a different environment

Refresher on catching exceptions:

try {
    await YOUR_CALL
} catch (e) {
    print(e.status, e.body, e.headers)
}

Namespace

In the interest of making the SDK follow conventions, we made the following namespace changes relative to the language agnostic resources up top.

  1. dashes - are removed in favor of camelCase
  2. all other non-alphanumeric symbols, including spaces, are removed.

For example:

  • get-campaigns becomes getCampaigns
  • Track & Identify becomes TrackIdentify

Parameters & Arguments

The parameters follow the same naming conventions as the resource groups and operations.

We stick to the following convention for parameters/arguments

  1. All parameters are passed as function args.
  2. All optional params, as well as all Body and Form Data params (including required ones), are passed in a single object param.
  3. All query and path params that are tagged as required in the docs are passed as positional args.
  4. There is no need to pass in your private api_key for any operations, as it is defined upon ConfigWrapper instantiation; public key is still required where its used.