HomeGuidesAPI Reference
ChangelogHelp CenterCommunityContact Us
Guides

Application objects for app partners

Learn how to build shared schema custom objects that automatically appear in your installer's Klaviyo accounts when they install your app.

Before you begin

Before you start, check out the general API overview and the Custom Objects API overview to familiarize yourself
with the core custom objects data model.

Application objects build on custom objects by introducing a shared schema that you define one
time in your developer account and that automatically becomes available in every Klaviyo account
that installs your app. This enables your app to sync structured, stateful data (e.g.,
reservations, loyalty rewards, subscriptions) that can be linked to your customers' Klaviyo profiles.

You will learn

This guide covers:

  • How application objects differ from standard custom objects
  • How to create an application object using the Custom Objects Definition APIs
  • The review and approval process for getting your application object into production

🚧

The Custom Objects Definition APIs used in this guide are in Beta and require the revision header revision: 2026-01-15.pre. The data ingestion endpoints (Create Data Source, Bulk Create Data Source Records) use the stable revision revision: 2025-07-15.

🚧

This API requires the following scopes:

  • custom-objects:read
  • custom-objects:write

You must add these scopes to your app and include them in your install URL parameters.
Customers who have already installed your app will need to re-authenticate to accept
the new scopes for object data to begin syncing.

How application objects work

Standard custom objects use a private schema where each Klaviyo account defines and
manages its own objects independently. Application objects use a shared schema, which means:

  • You define the object type one time in your developer or staging account, tied to your application ID.
  • The object type is automatically linked to every Klaviyo account that installs your app.
  • Schema updates propagate to all accounts using the shared schema when you publish a new version.
  • You control the object definition — your customers do not need to set up or configure the object themselves.

Key concepts

ConceptDescription
Shared schemaAn object schema with visibility set to "shared". It is referenced across all accounts that install your app.
NamespaceA string in the format applications/<your_app_id> that associates the schema with your application.
LinkingWhen a customer installs your app, the shared schema object type is automatically linked to their account.
UnlinkingWhen a customer uninstalls your app, the object type is unlinked. Object records persist in the customer's account but no longer receive schema updates.

Step 1: Plan your application object

Before you start building, plan your object's structure:

  1. Define your object type. What real-world concept does it represent? Examples: Reservation, Reward, Subscription, Wishlist Item, Review.
  2. Identify properties. What fields should each object record contain? Each object can have up to 30 properties (not including the unique identifier). Supported data types: STRING, INT, FLOAT, BOOLEAN, TIMESTAMP.
  3. Determine the profile relationship. How does each record connect to a Klaviyo profile? You must provide at least one profile identifier (email, phone number, external ID, or Klaviyo ID).
  4. Consider use cases. How will Klaviyo customers use this data? Think about segmentation (e.g., "customers with an active reservation"), flow triggers (e.g., "reservation check-in date is tomorrow"), and template personalization (e.g., displaying reservation details in a pre-arrival email).

🚧

Plan carefully before building. The Custom Objects API does not currently support deletion or breaking changes to shared schemas. Mistakes are difficult to remediate after your object is published.

Step 2: Build your application object in staging

Build and test your application object in a staging or development account before it can be reviewed and promoted to production. Use your staging application ID throughout this process.

The creation workflow follows the same steps as programmatic custom objects setup, with two key differences:

  • Set visibility to "shared" (instead of "private") on both the object type and data source.
  • Set namespace to "applications/<your_staging_app_id>" on both the object type and data source.

Both the object type and data source must use the same namespace and visibility.

Step 2a: Create a data source

Create a data source using the Create Data Source endpoint.

{
    "data": {
        "type": "data-source",
        "attributes": {
            "visibility": "shared",
            "namespace": "applications/<YOUR_STAGING_APP_ID>",
            "title": "Reservation Database",
            "description": "The source of truth for reservations from our platform"
        }
    }
}

Save the returned id — you'll need it when configuring source mappings in Step 2e.

Step 2b: Create an object type

Create an object type using the Create Object Type endpoint. This automatically creates a draft schema and an empty source mapping.

{
    "data": {
        "type": "object-type",
        "attributes": {
            "visibility": "shared",
            "namespace": "applications/<YOUR_STAGING_APP_ID>",
            "title": "Reservation",
            "description": "Customer reservation information synced from our platform"
        }
    }
}

Save the draft_schema_id from the response, you need it for the next several steps.

Step 2c: Update the object schema

Update the draft schema with your properties using the Update Object Schema endpoint. Each property needs a unique numeric id and a data type.
The {"id": "0", "name": "id", "type": "STRING"} property is automatically created when creating an object type, is required for all schemas, and the name and type cannot be changed.
The identifier is mapped from the id_path in source-mapping and will be converted to a string data type regardless of the source field's original data type and name.

{
    "data": {
        "id": "<DRAFT_SCHEMA_ID>",
        "type": "object-schema",
        "attributes": {
            "title": "Reservation",
            "properties": [
                {"id": "0", "name": "id", "type": "STRING", "description": "Unique reservation identifier"},
                {"id": "1", "name": "check_in_date", "type": "TIMESTAMP", "description": "Scheduled check-in date"},
                {"id": "2", "name": "check_out_date", "type": "TIMESTAMP", "description": "Scheduled check-out date"},
                {"id": "3", "name": "status", "type": "STRING", "description": "Current reservation status (e.g., confirmed, checked_in, cancelled)"},
                {"id": "4", "name": "guest_count", "type": "INT", "description": "Number of guests"}
            ],
            "required": []
        }
    }
}

📘

You can only update a schema while it is in DRAFT status. Once activated, the schema is locked to only allow new non-required properties. Plan your properties carefully.

Step 2d: Create a profile relationship

Link your object to Klaviyo profiles using the profile object schema relationships endpoint on your draft schema.

POST /api/object-schemas/<DRAFT_SCHEMA_ID>/relationships/profile-object-schemas
{
    "data": [
        {
            "type": "profile-object-schema",
            "meta": {
                "name": "reservation_guest",
                "description": "The guest associated with this reservation"
            }
        }
    ]
}

Save the relationship_id from the response — you'll need it when configuring the source mapping.

🚧

The type must be "profile-object-schema" (not "object-schema"). Using the wrong type returns a 400 error.

Step 2e: Update the source mapping

Configure how your data source fields map to schema properties and relationships using the Update Source Mapping endpoint. The source mapping ID is the same as your draft schema ID.

{
    "data": {
        "type": "source-mapping",
        "id": "<DRAFT_SCHEMA_ID>",
        "attributes": {
            "property_mappings": [
                {"id": "1", "type": "simple", "source": {"source_id": "<DATA_SOURCE_ID>", "id_path": "$['reservation_id']", "data_path": "$['check_in_date']"}},
                {"id": "2", "type": "simple", "source": {"source_id": "<DATA_SOURCE_ID>", "id_path": "$['reservation_id']", "data_path": "$['check_out_date']"}},
                {"id": "3", "type": "simple", "source": {"source_id": "<DATA_SOURCE_ID>", "id_path": "$['reservation_id']", "data_path": "$['status']"}},
                {"id": "4", "type": "simple", "source": {"source_id": "<DATA_SOURCE_ID>", "id_path": "$['reservation_id']", "data_path": "$['guest_count']"}}
            ],
            "relationship_mappings": [
                {
                    "relationship_id": "<RELATIONSHIP_ID_FROM_STEP_2D>",
                    "type": "simple",
                    "source": {
                        "source_id": "<DATA_SOURCE_ID>",
                        "id_path": "$['reservation_id']",
                        "update_strategy": "replace",
                        "type": "profile",
                        "related_id_paths": [
                            {
                                "identifier_type": "email",
                                "path": "$['email']"
                            }
                        ]
                    }
                }
            ]
        }
    }
}

Step 2f: Ingest test data

Ingest records into your data source using the Bulk Create Data Source Records endpoint. Ingest at least a few records before activating to confirm your data and mappings are configured correctly.

{
    "data": {
        "type": "data-source-record-bulk-create-job",
        "attributes": {
            "data-source-records": {
                "data": [
                    {
                        "type": "data-source-record",
                        "attributes": {
                            "record": {
                                "reservation_id": "RES-001",
                                "check_in_date": "2026-05-15T15:00:00Z",
                                "check_out_date": "2026-05-18T11:00:00Z",
                                "status": "confirmed",
                                "guest_count": 2,
                                "email": "[email protected]"
                            }
                        }
                    }
                ]
            }
        },
        "relationships": {
            "data-source": {
                "data": {
                    "type": "data-source",
                    "id": "<DATA_SOURCE_ID>"
                }
            }
        }
    }
}

Step 2g: Activate the schema

Once your schema, profile relationship, and source mapping are fully configured and you have ingested test data, activate the schema using the Update Object Schema endpoint:

{
    "data": {
        "type": "object-schema",
        "id": "<DRAFT_SCHEMA_ID>",
        "attributes": {
            "status": "ACTIVE"
        }
    }
}

Activation validates your entire configuration and processes all ingested raw data into custom object records.
The response shows status PUBLISHING while records are being processed, this typically transitions to ACTIVE
within a few minutes depending on data volume.

At this point, the object is published for your staging application and ready to be tested.

Step 3: Test your application object

Before submitting for review, verify that your application object works correctly:

  1. Confirm object linking. Install your staging app in a separate test account and verify that the object type appears automatically.
  2. Ingest records. Send data through your app and confirm that records appear on the correct profiles.
  3. Test segmentation. Create a segment using your object's properties (e.g., "status equals confirmed") and verify it includes the expected profiles.
  4. Test flow triggers. If applicable, set up a date-triggered flow using one of your object's timestamp properties and verify it triggers correctly.
  5. Test template personalization. Create an email template that pulls data from your object and verify the personalization tags render correctly.
Object appearing on a customer profile after app installation and data ingestion

Step 4: Submit for review

Once you have tested your application object in staging, submit it for Klaviyo's review. The review ensures your object
follows best practices and is correctly structured before it goes live with customers.

Review submission process

  1. Add custom object scopes to your production app. In the Klaviyo UI, navigate to your production app settings and add the custom-objects:read and custom-objects:write scopes. Also include these scopes in your install URL parameters.
  2. Submit the Application Object Review Form. Complete the form with the following details:
    • Your staging account ID
    • Your staging application ID
    • A description of your object type, its properties, and intended use cases
    • Confirmation that your object is built and activated in your staging account
  3. Grant Klaviyo remote access. The review team may request remote edit access to your staging account to test your object. Follow these instructions to grant access.

What happens during review

The Klaviyo review team will:

  • Verify your object schema is correctly structured with appropriate property names, types, and descriptions
  • Confirm the profile relationship is properly configured
  • Test data ingestion and record creation in your staging environment
  • Validate that the object supports the intended use cases (segmentation, flows, personalization)
  • Provide feedback on any required changes

Review outcomes

OutcomeNext steps
ApprovedKlaviyo clones your object from your staging application to production. See Step 5.
Minor fixes neededThe review team requests specific updates. Make the changes and confirm.
Significant issuesThe review team provides detailed feedback. Address the issues, re-test, and resubmit.

Important: Do not create your application object directly in your production app.
Always build in staging first. The review team uses tooling to clone approved
objects from staging to production to ensure consistency.

Step 5: Go live in production

After your application object passes review, the Klaviyo team clones it to your production application on your behalf.

What Klaviyo does

  1. Clones your approved object definition (schema, source mapping, relationships) from your staging app to your production app.
  2. Associates the shared schema with your published production application.
  3. Notifies you with your new production data source ID and confirmation of the cloning.

What you need to do

  1. Update your app to use the new data source ID. Your production data source ID is different from your staging data source ID. Update your app code to send data to the production data source.
  2. Find your production data source ID. Navigate to Integrations > Developers > Manage Apps > [Your App] > Objects > (three-dot menu) > View Definition > View sample payload.
  3. Encourage customers to re-authenticate. Customers who installed your app before you added custom object scopes need to re-authenticate to accept the new scopes. Until they do, the application object is not active for their account.
  4. Begin ingesting production data. Use the Bulk Create Data Source Records endpoint to start syncing live data.

Updating your application object

After your application object is live, you can update it by creating a new draft version of your schema:

  1. Create a draft version of your published object type using the Create Draft Schema endpoint.
  2. Update the draft schema with new or modified properties.
  3. Update the source mapping to reflect any changes.
  4. Activate the new schema version.

When you activate an updated schema, the changes propagate to all accounts that have installed your app. Existing object records are re-processed against the new schema.

🚧

Schema updates are additive only. You cannot remove existing properties or change a property's data type. Plan your schema carefully from the start.

Limitations and best practices

Current limitations

  • No deletion. You cannot delete a shared schema object type via the API. If you need an object deleted, contact Klaviyo support.
  • No breaking changes. You cannot remove properties, rename properties, or change property data types on an active schema.
  • Object type limit. Applications currently support up to 3 shared schema object types.
  • No object-to-object relationships. Object-to-object relationships are not currently supported. Each object type must relate directly to profiles or not at all.
  • Property limits. Each object can have up to 30 properties (not including the unique identifier). Each property must not exceed 2 KB in size, and total record size must not exceed 8 KB.

Best practices

  • Use descriptive property names. Your customers see property names in the Klaviyo UI when building segments, flows, and templates. Use clear, human-readable names (e.g., check_in_date rather than ci_dt).
  • Include a status property. If your object represents something with a lifecycle (e.g., a reservation, subscription, or reward), include a status property so customers can segment by state.
  • Provide timestamp properties. Timestamp properties enable date-triggered flows, which are one of the most powerful use cases for application objects.
  • Keep objects separate. Model each distinct entity as its own object type rather than combining multiple concepts into one.
  • Test thoroughly in staging. Verify segmentation, flows, and template personalization all work correctly before submitting for review.

Flow templates (optional)

Once your application object is live in production, you can create object-triggered flow templates for inclusion in Klaviyo's flow template library. This helps your customers quickly set up automations using your object data.

For documentation on flow template requirements and submission, see Submit flow templates for your app.

📘

The flow template documentation currently states that flows must be event-triggered. For application objects, create object-triggered flows instead. You can reference object data within the emails in these flows.

Additional resources