HomeGuidesAPI Reference
ChangelogHelp CenterCommunityContact Us
Guides

Upgrading to Revision 2023-07-15 or newer

Learn about the various breaking changes made across endpoints with the 2023-07-15 revision.

🚧

v1/v2 legacy APIs retired on June 30, 2024.

To learn more about Klaviyo’s API lifecycle, check out our updated API versioning and deprecation policy.

Klaviyo is standardizing how we handle relationships in our APIs and implemented consistently typed objects across API endpoints. Following the 2023-07-15 revision changes, you can create a profile in our APIs in the same shape, regardless of whether you’re calling the profiles endpoint or the events endpoint.

Use this guide to upgrade from an older revision, to revision 2023-07-15 or newer.

The kinds of changes include:

  • 1:1 relationships now use singular tense and an object, instead of plural and an array.
    • Example: GET https://a.klaviyo.com/api/flow-actions/{flow_action_id}/?include=flow , now flow instead of flows.
  • Related object IDs relocated from the attributes payload to relationships.
    • Example: POST https://a.klaviyo.com/api/tags/.
  • Specifying a relationship between two Klaviyo objects allows for improved consistency and greater interoperability across endpoints.
    • Example: You can now create/update a profile for an event in the same way you would when using the profiles API directly with a POST request to https://a.klaviyo.com/api/events/.

Events API

Why

Events are related to other top-level profile and metric objects. Consistently specify the attributes for profiles, as well as metrics, when creating events for a particular profile or creating or updating a profile.

You can also specify a profile for an event in the same way as using the Profiles API.

Before and after

POST request to https://a.klaviyo.com/client/events:

{  
  "data": {  
    "type": "event",  
    "attributes": {  
      "profile": {  
        "$email": "[email protected]",  
        "$phone_number": "+19148675309",  
        "$kid": "12234345",  
        "$id": "abc123",  
        "$exchange_id": "ksdfxl-sdfssdf",  
        "fun fact": "i like coffee",  
      },  
      "metric": {  
        "name": "Viewed Product"  
      },  
      "properties": {  
        "itemId": "123"  
      },  
      "time": "2022-11-08T00:00:00",  
      "value": 9.99  
    }  
  }  
}
{  
  "data": {  
    "type": "event",  
    "attributes": {  
      "profile": {  
        "data": {  
           "type": "profile",  
           "id": "12234345",  
           "attributes": {  
              "email": "[email protected]",  
              "phone_number": "+19148675309",  
              "anonymous_id": "123456",  
              "external_id": "abc123",  
              "\_kx": "ksdfxl-sdfssdf",  
              "properties": {  
                 "fun fact": "i like coffee"  
              }  
           }  
      },  
      "metric": {  
        "data": {  
          "type": "metric",  
          "attributes": {  
     "name": "Viewed Product"  
    }  
        }  
      },  
      "properties": {  
        "itemId": "123"  
      },  
      "time": "2022-11-08T00:00:00",  
      "value": 9.99  
    }  
  }  
}

The metric_id and profile_id have been removed from the top-level attributes on the event payload.
The relationships keys are now singular.

Why

The metric and profile IDs are related object IDs and can be accessed under relationships.

The relationships between an event and profile and event and metric are 1:1, which should be specified as singular.

Before and after

GET request to /api/events/{event_id}:

{  
  "data": {  
    "type": "event",  
    "attributes": {  
      "metric_id": "AbC123",  
      "profile_id": "01F2VWQ645BES947MP1BPAKVMB",  
      "timestamp": 1688154729,  
      "event_properties": {  
         ...  
      },  
      "datetime": "2023-06-30 19:52:09+00:00",  
      "uuid": "98fbfa80-177f-11ee-8001-f71585a038b4"  
    },  
    "relationships": {  
        "profiles": {  
            "data": [  
                {"type": "profile", "id": "01F2VWQ645BES947MP1BPAKVMB"}  
            ]  
        },  
        "metrics": {  
            "data": [  
                {"type": "metric", "id": "AbC123"}  
            ]  
        },  
    }  
}
{  
  "data": {  
    "type": "event",  
    "attributes": {  
      "timestamp": 1688154729,  
      "event_properties": {  
         ...  
      },  
      "datetime": "2023-06-30 19:52:09+00:00",  
      "uuid": "98fbfa80-177f-11ee-8001-f71585a038b4"  
    },  
    "relationships": {  
        "profile": {  
            "data": {"type": "profile", "id": "01F2VWQ645BES947MP1BPAKVMB"}  
        },  
        "metric": {  
            "data": {"type": "metric", "id": "AbC123"}  
        },
    }
}

Flows API

When including the related flow for a flow action, or related action for a message, specify as singular instead of plural.

Why

This is a to-one relationship, which should be specified as singular.

Before and after

GET request to /api/flow-actions/{flow_action_id}/?include=flow:

{  
  "data": {  
    "type": "flow-action",  
    "attributes": {...},  
    "relationships": {  
        "flows": {  
            "data": [  
                {"type": "flow", "id": "HgkVeu"}  
            ]  
        }  
    }  
}
{  
  "data": {  
    "type": "flow-action",  
    "attributes": {...},  
    "relationships": {  
        "flow": {  
            "data": {"type": "flow", "id": "HgkVeu"}  
        }  
    }  
}

The relationship to the flow will return a singular object instead of an array.

GET request to /api/flow-actions/{flow_action_id}/relationships/flow/:

{  
    "data": [  
        {  
            "type": "flow",  
            "id": "HgkVeu"  
        }  
    ]  
}
{  
    "data": {  
        "type": "flow",  
        "id": "HgkVeu"  
    }  
}

Tags API

When creating a tag, the related tag group must now be specified as a relationship instead of using a tag_group_id field.

Why

This is the standard JSON:API method for assigning relationships when creating resources.

Before and after

POST request to /api/tags/:

{  
  "data": {  
    "type": "tag",  
    "attributes": {  
      "name": "My Tag",  
      "tag_group_id": "zyxw9876-vu54-ts32-rq10-zyxwvu654321"  
    }  
  }  
}
{  
  "data": {  
    "type": "tag",  
    "attributes": {  
      "name": "My Tag",  
    },  
    "relationships": {  
      "tag-group": {  
        "type": "tag-group",  
        "id": "zyxw9876-vu54-ts32-rq10-zyxwvu654321"  
      }  
    }  
  }  
}

The response from this endpoint will return a single object now, the related tag group, instead of a list containing one object.

Why

Singular-to-one relationships (i.e., "tag-group", not "tag-groups") will return single objects.

Before and after

GET request to /api/tags/1/tag-group/:

{  
  "data": [  
    {  
      "type": "tag-group",  
      "id": "zyxw9876-vu54-ts32-rq10-zyxwvu654321"  
      ...  
    }  
  ]  
}
{  
  "data": {  
      "type": "tag-group",  
      "id": "zyxw9876-vu54-ts32-rq10-zyxwvu654321"  
      ...  
  }  
}

Campaigns API

When using the campaigns API, the related campaign message (for campaigns) and the related campaign (for campaign messages) will no longer be returned in a message or campaign_id string field. Instead it will be returned as a relationship, in the relationship section of the response.

When using the Campaign Message API, any related templates will be referenced using relationships.

Why

This is the standard JSON:API method for posting and returning relationship data from a resource.

Before and after

GET request to /api/campaigns/{campaign_id}/:

{  
  "data": {  
    "type": "campaign",  
    "id": "1",  
    "attributes": {  
      ...  
      "message": "123"  
    }  
  }  
}
{  
  "data": {  
    "type": "campaign",  
    "id": "1",  
    "attributes": {  
      ...  
    },  
    "relationships": {  
      "campaign-messages": {  
        "data": [  
          {  
            "type": "campaign-message",  
            "id": "123"  
          }  
        ]  
      }  
    }  
  }  
}

GET request to /api/campaign-messages/{campaign_message_id}/:

{  
  "data": {  
    "type": "campaign-message",  
    "id": "1",  
    "attributes": {  
      ...  
      "content": {  
        "subject": "Hello",  
        "template_id": "1",  
        "template_name": "My Template"  
      }  
    }  
  }  
}
{  
  "data": {  
    "type": "campaign-message",  
    "id": "1",  
    "attributes": {  
      ...  
      "content": {  
        "subject": "Hello",  
      }  
    },  
    "relationships": {  
      "templates": {  
        "data": {  
          "type": "template",  
          "id": "1"  
        }  
      }  
    }  
  }  
}

GET request to /api/campaign-messages/{campaign_message_id}/?include=template:

{  
  "data": {  
    "type": "campaign-message",  
    "id": "1",  
    "attributes": {  
      ...  
      "content": {  
        "subject": "Hello",  
        "template_id": "1",  
        "template_name": "My Template"  
      }  
    }  
  }  
}
{  
  "data": {  
    "type": "campaign-message",  
    "id": "1",  
    "attributes": {  
      ...  
      "content": {  
        "subject": "Hello",  
      }  
    },  
    "relationships": {  
      "template": {  
        "data": {  
          "type": "template",  
          "id": "1"  
        }  
      }  
    }  
  },  
  "included": [  
    {  
      "type": "template",  
      "id": "1",  
      "attributes": {  
        "name": "My Template"  
      }  
    }  
  ]  
}

Catalogs API

When creating a catalog variant, the related item will be specified as a singular-to-one relationship using the item field, rather than a list containing one item using items.

Why

This relationship is singular, and should be specified as a single item.

Before and after

POST request to /api/catalog-variants/:

{  
  "data": {  
    "type": "catalog-variant",  
    "attributes": {  
      ...  
    },  
    "relationships": {  
      "items": {  
        "data": [  
          {  
            "type": "catalog-item",  
            "id": "$custom:::$default:::SAMPLE-DATA-ITEM-1"  
          }  
        ]  
      }  
    }  
  }  
}
{  
  "data": {  
    "type": "catalog-variant",  
    "attributes": {  
      ...  
    },  
    "relationships": {  
      "item": {  
        "data": {  
          "type": "catalog-item",  
          "id": "$custom:::$default:::SAMPLE-DATA-ITEM-1"  
        }  
      }  
    }  
  }  
}

The request payload for the bulk catalog APIs is changing slightly: an additional data element is inserted into the payload before the resource array.

Why

This is standardization to align with the similar structure in the relationships section of payloads.

Before and after

POST request to /api/catalog-item-bulk-create-jobs/:

{  
  "data": {  
    "type": "catalog-item-bulk-create-job",  
    "attributes": {  
      "items": [  
        {"type": "catalog-item", ...}  
      ]  
    }  
  }  
}
{  
  "data": {  
    "type": "catalog-item-bulk-create-job",  
    "attributes": {  
      "items": {  
        "data": [  
          {"type": "catalog-item", ...}  
        ]  
      }  
    }  
  }  
}

Client API and Profiles API

When subscribing a profile, the related list will be specified as a relationship instead of an embedded list_id, and the profiles to subscribe will be specified as profile resource objects instead of email, phone_number, or id.

Why

This is the standard JSON:API method for assigning relationships when creating resources.

Before and after

POST request to /api/profile-subscription-bulk-create-jobs/:

{  
  "data": {  
    "type": "profile-subscription-bulk-create-job",  
    "attributes": {  
      "list_id": "Y6nRLr",  
      "subscriptions": [  
        {"email": "[email protected]", "channels": {...}},  
        ...  
      ],  
    }  
  }  
}
{  
  "data": {  
    "type": "profile-subscription-bulk-create-job",  
    "attributes": {  
      "profiles": {  
        "data": [  
          {  
            "type": "profile",  
            "attributes": {  
              "email": "[email protected]",  
              "subscriptions": {...}  
        	  },  
             ...  
          ]  
        }  
      }  
    },  
    "relationships": {  
      "list": {  
        "data": {"type": "list", "id": "Y6nRLr"}  
      }  
    }  
  }  
}

List and profiles are specified via relationships, and the URL path and type have been updated.

Before and after

POST request to /api/profile-unsubscription-bulk-create-jobs/:

{  
  "data": {  
    "type": "profile-subscription-bulk-create-job",  
    "attributes": {  
      "list_id": "Y6nRLr",  
      "subscriptions": [  
        {"email": "[email protected]", "channels": {...}},  
        ...  
      ],  
    }  
  }  
}
{  
  "data": {  
    "type": "profile-subscription-bulk-delete-job",  
    "attributes": {  
      "profiles": {  
        "data": [  
          {  
            "type": "profile",  
            "attributes": {  
              "email": "[email protected]"  
        	  },  
          },  
          ...  
         ]  
        }  
      }  
    },  
    "relationships": {  
      "list": {  
        "data": {"type": "list", "id": "Y6nRLr"}  
      }  
    }  
  }  
}

Profiles are specified under profiles, and the URL path and resource type have been updated.

Before and after

POST request to /api/profile-suppression-bulk-create-jobs/:

{  
  "data": {  
    "type": "profile-suppression-bulk-create-job",  
    "attributes": {  
      "suppressions": [  
          {  
            "email": "[email protected]",  
          },  
          ...  
      ]  
    }  
  }  
}
{  
  "data": {  
    "type": "profile-suppression-bulk-create-job",  
    "attributes": {  
      "profiles": {  
        "data": [  
          {  
           "type": "profile",  
            "attributes": {  
              "email": "[email protected]",  
           },  
           ...  
         ]  
      }  
    }  
  }  
}

Profiles are specified under profiles, and the URL path and resource type have been updated.

Before and after

POST request to /api/profile-unsuppression-bulk-create-jobs:

{  
  "data": {  
    "type": "profile-unsuppression-bulk-create-job",  
    "attributes": {  
      "suppressions": [  
        {  
          "email": "[email protected]"  
        }  
      ]  
    }  
  }  
}
{  
  "data": {  
    "type": "profile-suppression-bulk-delete-job",  
    "attributes": {  
      "profiles": {  
        "data": [  
          {  
           "type": "profile",  
            "attributes": {  
              "email": "[email protected]",  
           },  
           ...  
         ]  
      }  
    }  
  }  
}

Data Privacy API

When requesting deletion of a profile, the related profile will be specified as a relationship to the profile resource instead of top level identifiers.

Why

This is the standard JSON:API method for specifying relationships to other resources.

Before and after

POST request to /api/data-privacy-deletion-jobs/:

{  
  "data": {  
    "type": "data-privacy-deletion-job",  
    "attributes": {  
      "profile_id": "01F2VWQ645BES947MP1BPAKVMB",  
      "email": "[email protected]",  
      "phone_number": "+15005550006"  
    }  
  }  
}
{  
  "data": {  
    "type": "data-privacy-deletion-job",  
    "attributes": {  
      "profile": {  
        "data": {  
          {  
            "type": "profile",  
            "id": "01F2VWQ645BES947MP1BPAKVMB",  
            "attributes": {  
              "email": "[email protected]",  
              "phone_number": "+15005550006"  
            }  
          }  
        }  
      }  
    }  
  }  
}