Method reference for the App API client. See the README for installation and cross-cutting behavior (regions, retries, and promise handling).
To use the Customer.io Transactional API, import our API client and initialize it with an app key and create a request object of your message type.
Create a new SendEmailRequest object containing:
transactional_message_id: the ID of the transactional message you want to send, or thebody,from, andsubjectof a new message.to: the email address of your recipients- an
identifiersobject containing the email and/oridof your recipient. If the person you reference by email or ID does not exist, Customer.io creates them. - a
message_dataobject containing properties that you want reference in your message using Liquid. - You can also send attachments with your message with
attach, but you need to read the file to a buffer (withfs.readFileSync, for example); you cannot attach raw, base64-encoded data directly from a variable.
Use sendEmail referencing your request to send a transactional message. Learn more about transactional messages and SendEmailRequest properties.
const fs = require("fs");
const { APIClient, SendEmailRequest, RegionUS, RegionEU } = require("customerio-node");
const api = new APIClient("app-key", { region: RegionUS });
const request = new SendEmailRequest({
to: "person@example.com",
transactional_message_id: "3",
message_data: {
name: "Person",
items: {
name: "shoes",
price: "59.99",
},
products: [],
},
identifiers: {
email: "person@example.com",
},
});
// (optional) attach a file to your message.
// Note that you need to read the file to a buffer;
// you can't simply attach raw, base64-encoded data.
request.attach("receipt.pdf", fs.readFileSync("receipt.pdf"));
api
.sendEmail(request)
.then((res) => console.log(res))
.catch((err) => console.log(err.statusCode, err.message));Create a new SendPushRequest object containing:
transactional_message_id: the ID or trigger name of the transactional message you want to send.- an
identifiersobject containing theidoremailof your recipient. If the profile does not exist, Customer.io will create it.
Use sendPush referencing your request to send a transactional message. Learn more about transactional messages and sendPushRequest properties.
const { APIClient, SendPushRequest, RegionUS, RegionEU } = require("customerio-node");
const api = new APIClient("app-key", { region: RegionUS });
const request = new SendPushRequest({
transactional_message_id: "3",
message_data: {
name: "Person",
items: {
name: "shoes",
price: "59.99",
},
products: [],
},
identifiers: {
id: "2",
},
});
api
.sendPush(request)
.then((res) => console.log(res))
.catch((err) => console.log(err.statusCode, err.message));Create a new SendWhatsAppRequest object containing:
transactional_message_id: the ID or trigger name of the transactional message you want to send.- an
identifiersobject containing theidoremailof your recipient. If the profile does not exist, Customer.io will create it. to: an E.164-formatted phone number. Optional only when the referencedtransactional_message_idalready defines it.
Use sendWhatsApp referencing your request to send a transactional message. Learn more about transactional messages.
const { APIClient, SendWhatsAppRequest, RegionUS, RegionEU } = require("customerio-node");
const api = new APIClient("app-key", { region: RegionUS });
const request = new SendWhatsAppRequest({
to: "+15558675309",
transactional_message_id: "3",
message_data: {
name: "Person",
},
identifiers: {
id: "2",
},
});
api
.sendWhatsApp(request)
.then((res) => console.log(res))
.catch((err) => console.log(err.statusCode, err.message));Trigger an email broadcast using the broadcast ID. You can also optionally pass along custom data that will be merged with the liquid template, and additional conditions to filter recipients.
api.triggerBroadcast(1, { name: "foo" }, { segment: { id: 7 } });You can also use emails or ids to select recipients, and pass optional API parameters such as email_ignore_missing.
api.triggerBroadcast(1, { name: "foo" }, { emails: ["example@emails.com"], email_ignore_missing: true });You can learn more about the available recipient fields here.
Both data and recipients are optional. Omitting recipients sends the broadcast to its configured recipients. Note that the parameters are positional: to pass recipients without data, pass undefined for data — passing the recipient selector as the second argument would send it as liquid data instead.
api.triggerBroadcast(1); // broadcast's configured recipients
api.triggerBroadcast(1, undefined, { emails: ["example@emails.com"], email_ignore_missing: true });- id: String or number (required)
- data: Object (optional)
- recipients: Object (optional)
Returns customer object with given email.
api.getCustomersByEmail("test@test.com");You can learn more about the available recipient fields here.
- email: String (required)
Returns a list of attributes for a customer profile.
api.getAttributes("1", "id");OR
const { IdentifierType } = require("customerio-node");
api.getAttributes("1", IdentifierType.ID);You can learn more about the available recipient fields here.
- id: Customer identifier, String or number (required)
- id_type: One of the ID types - "id" / "email" / "cio_id" (default is "id")
Look up a person's activities (events, attribute changes, message activity, etc.).
api.getCustomerActivities("1", { type: "event", name: "purchase", limit: 50 });- customerId: Customer identifier, String or number (required)
- options: Object (optional)
- idType: One of "id" / "email" / "cio_id" (defaults to "id")
- start: Pagination cursor from a previous page's
next - limit: Maximum number of results
- type: Filter to a single activity type
- name: Filter to activities with this name
Look up messages sent to a person.
api.getCustomerMessages("1", { start_ts: 1719792000, end_ts: 1719878400 });- customerId: Customer identifier, String or number (required)
- options: Object (optional) —
idType,start,limit, andstart_ts/end_tsUnix timestamp bounds
Look up a person's relationships to objects.
api.getCustomerRelationships("1", { limit: 20 });- customerId: Customer identifier, String or number (required)
- options: Object (optional) —
start,limit
Look up the segments a person belongs to.
api.getCustomerSegments("1", IdentifierType.Id);- customerId: Customer identifier, String or number (required)
- idType: One of "id" / "email" / "cio_id" (default is "id")
Look up a person's subscription (topic) preferences.
api.getCustomerSubscriptionPreferences("1", { language: "es-ES" });- customerId: Customer identifier, String or number (required)
- options: Object (optional) —
idType, andlanguage(an IETF language tag used to localize topic names)
Search for people matching a filter expression.
api.searchCustomers({ and: [{ segment: { id: 7 } }] }, { limit: 100 });- filter: A segment/attribute filter expression (and/or/not) (required)
- options: Object (optional) —
start,limit
Look up attributes and devices for a set of people in one request.
api.getCustomersAttributes(["1", "2", "3"]);- ids: A non-empty array of customer identifiers (required)
Get an object's attributes.
api.getObjectAttributes(1, "acme", "object_id");- objectTypeId: The object type's numeric id (required)
- objectId: The object's identifier value (required)
- idType: One of "object_id" / "cio_object_id" (defaults to "object_id")
Get an object's relationships to people.
api.getObjectRelationships(1, "acme", { limit: 20 });- objectTypeId: The object type's numeric id (required)
- objectId: The object's identifier value (required)
- options: Object (optional) —
idType("object_id" / "cio_object_id"),start,limit
Find objects of a given type matching a filter expression.
api.findObjects(1, { and: [{ attribute: { field: "plan", operator: "eq", value: "pro" } }] });- objectTypeId: The object type's numeric id (required)
- filter: A filter expression (and/or/not) (required)
- options: Object (optional) —
start,limit
List the object types defined in your workspace.
api.listObjectTypes();List activities across your workspace.
api.listActivities({ type: "event", customerId: "1", idType: IdentifierType.Id });- options: Object (optional) —
start,limit,type,name,deleted,customerId,idType
List the segments in your workspace.
api.listSegments();Create a manual segment.
api.createSegment({ name: "VIPs", description: "High-value customers" });- segment: Object (required) —
name(required) and optionaldescription
Get a single segment's metadata.
api.getSegment(7);- segmentId: The segment's numeric id (required)
Delete a manual segment.
api.deleteSegment(7);- segmentId: The segment's numeric id (required)
Get the number of people in a segment.
api.getSegmentCustomerCount(7);- segmentId: The segment's numeric id (required)
List the people who belong to a segment.
api.getSegmentMembership(7, { limit: 100 });- segmentId: The segment's numeric id (required)
- options: Object (optional) —
start,limit
Get the campaigns, newsletters, and other resources that use a segment.
api.getSegmentUsedBy(7);- segmentId: The segment's numeric id (required)
List the subscription topics defined in your workspace.
api.listSubscriptionTopics();List the subscription channels configured in your workspace.
api.listSubscriptionChannels();Generate a subscription center token for a person, used to authenticate a hosted subscription-center link.
api.getSubscriptionCenterToken("1");- customerId: The person's identifier value (required)
List the transactional messages in your workspace.
api.listTransactionalMessages();Get a single transactional message's metadata.
api.getTransactionalMessage(3);- transactionalId: The transactional message's numeric id (required)
List all content variants of a transactional message.
api.getTransactionalMessageContents(3);- transactionalId: The transactional message's numeric id (required)
Get a single-language translation of a transactional message.
api.getTransactionalMessageLanguage(3, "en-US");- transactionalId: The transactional message's numeric id (required)
- language: The IETF language tag of the translation (required)
Update a single-language translation of a transactional message.
api.updateTransactionalMessageLanguage(3, "en-US", { subject: "Welcome!" });- transactionalId: The transactional message's numeric id (required)
- language: The IETF language tag of the translation (required)
- data: The translation fields to update
Get the individual deliveries (sends) of a transactional message.
api.getTransactionalMessageDeliveries(3, { metric: "delivered", limit: 50 });- transactionalId: The transactional message's numeric id (required)
- options: Object (optional) —
start,limit,metric,start_ts,end_ts,get_tracked_responses
Get delivery metrics for a transactional message over time.
api.getTransactionalMessageMetrics(3, { period: "days", steps: 14 });- transactionalId: The transactional message's numeric id (required)
- options: Object (optional) —
period("hours" / "days" / "weeks" / "months"),steps
Get link (click) metrics for a transactional message over time.
api.getTransactionalMessageLinkMetrics(3, { period: "weeks", steps: 4, unique: true });- transactionalId: The transactional message's numeric id (required)
- options: Object (optional) —
period,steps,unique
Update a transactional message's content variant.
api.updateTransactionalMessageContent(3, 5, { body: "Updated body" });- transactionalId: The transactional message's numeric id (required)
- contentId: The content variant's numeric id (required)
- data: The content fields to update
Return a list of your exports. Exports are point-in-time people or campaign metrics.
api.listExports();Return information about a specific export.
api.getExport(1);- export_id: String or number (required)
This endpoint returns a signed link to download an export. The link expires after 15 minutes.
api.downloadExport(1);- export_id: String or number (required)
Provide filters and attributes describing the customers you want to export. This endpoint returns export metadata; use the /exports/{export_id}/endpoint to download your export.
api.createCustomersExport({
filters: {
and: [
{
segment: {
id: 3,
},
},
],
},
});- filters: Object (required)
You can read more about the filter object syntax on the export customer data docs.
Provide filters and attributes describing the customers you want to export. This endpoint returns export metadata; use the /exports/{export_id}/endpoint to download your export.
api.createDeliveriesExport(1, {
start: 1666950084,
end: 1666950084,
attributes: ["attr_one"],
metric: "attempted",
drafts: false,
});- newsletter_id: String or number (required)
- options: Object
You can read more about the available options on the export deliveries data docs.
List the campaigns in your workspace.
api.listCampaigns();Get a single campaign's metadata.
api.getCampaign(9);- campaignId: The campaign's numeric id (required)
List a campaign's actions.
api.getCampaignActions(9, { start: "cursor" });- campaignId: The campaign's numeric id (required)
- options: Object (optional) —
start(pagination cursor)
Get a single action of a campaign.
api.getCampaignAction(9, 2);- campaignId: The campaign's numeric id (required)
- actionId: The action's numeric id (required)
Update an action of a campaign.
api.updateCampaignAction(9, 2, { body: "Updated body" });- campaignId: The campaign's numeric id (required)
- actionId: The action's numeric id (required)
- data: The action fields to update
Get a single-language translation of a campaign action.
api.getCampaignActionLanguage(9, 2, "en-US");- campaignId: The campaign's numeric id (required)
- actionId: The action's numeric id (required)
- language: The IETF language tag (required)
Update a single-language translation of a campaign action.
api.updateCampaignActionLanguage(9, 2, "fr", { subject: "Bonjour" });- campaignId: The campaign's numeric id (required)
- actionId: The action's numeric id (required)
- language: The IETF language tag (required)
- data: The translation fields to update
Get metrics for a single campaign action over time. Aggregated across all channels (no type filter).
api.getCampaignActionMetrics(9, 2, { version: "2", period: "days", steps: 7 });- campaignId: The campaign's numeric id (required)
- actionId: The action's numeric id (required)
- options: Object (optional) —
version("1" / "2"),res,tz,start,end,period,steps
Get link (click) metrics for a single campaign action over time.
api.getCampaignActionMetricsLinks(9, 2, { period: "weeks", steps: 4, unique: true });- campaignId: The campaign's numeric id (required)
- actionId: The action's numeric id (required)
- options: Object (optional) —
period,steps,unique
Get delivery metrics for a campaign over time.
api.getCampaignMetrics(9, { version: "1", res: "daily", start: 1719792000, end: 1719878400 });- campaignId: The campaign's numeric id (required)
- options: Object (optional) —
version("1" / "2"),type,res,tz,start,end,period,steps
Get link (click) metrics for a campaign over time.
api.getCampaignMetricsLinks(9, { period: "days", steps: 30, unique: true });- campaignId: The campaign's numeric id (required)
- options: Object (optional) —
period,steps,unique
Get a campaign's journey metrics (per-step conversion funnel) over a window.
api.getCampaignJourneyMetrics(9, { start: 1719792000, end: 1719878400, res: "daily" });- campaignId: The campaign's numeric id (required)
- options: Object (required) —
start,end, andresare all required
Get the individual messages (deliveries) sent by a campaign.
api.getCampaignMessages(9, { type: "email", metric: "delivered", limit: 50 });- campaignId: The campaign's numeric id (required)
- options: Object (optional) —
start,limit,type,metric,drafts,start_ts,end_ts,get_tracked_responses
Get the status of an API-triggered broadcast run. Pairs with api.triggerBroadcast.
api.getBroadcastTriggerStatus(1, 5);- broadcastId: The broadcast (campaign) id (required)
- triggerId: The trigger id returned by
triggerBroadcast(required)
Get the per-recipient errors for an API-triggered broadcast run.
api.getBroadcastTriggerErrors(1, 5, { limit: 100 });- broadcastId: The broadcast (campaign) id (required)
- triggerId: The trigger id (required)
- options: Object (optional) —
start,limit
List the broadcasts in your workspace.
api.listBroadcasts();Get a single broadcast's metadata.
api.getBroadcast(4);- broadcastId: The broadcast's numeric id (required)
List a broadcast's actions.
api.getBroadcastActions(4);- broadcastId: The broadcast's numeric id (required)
Get a single action of a broadcast.
api.getBroadcastAction(4, 2);- broadcastId: The broadcast's numeric id (required)
- actionId: The action's numeric id (required)
Update an action of a broadcast.
api.updateBroadcastAction(4, 2, { body: "Updated body" });- broadcastId: The broadcast's numeric id (required)
- actionId: The action's numeric id (required)
- data: The action fields to update
Get a single-language translation of a broadcast action.
api.getBroadcastActionLanguage(4, 2, "en-US");- broadcastId: The broadcast's numeric id (required)
- actionId: The action's numeric id (required)
- language: The IETF language tag (required)
Update a single-language translation of a broadcast action.
api.updateBroadcastActionLanguage(4, 2, "fr", { subject: "Bonjour" });- broadcastId: The broadcast's numeric id (required)
- actionId: The action's numeric id (required)
- language: The IETF language tag (required)
- data: The translation fields to update
Get metrics for a single broadcast action over time. Aggregated across all channels (no type filter).
api.getBroadcastActionMetrics(4, 2, { period: "days", steps: 7 });- broadcastId: The broadcast's numeric id (required)
- actionId: The action's numeric id (required)
- options: Object (optional) —
period,steps
Get link (click) metrics for a single broadcast action over time.
api.getBroadcastActionMetricsLinks(4, 2, { period: "weeks", steps: 4, unique: true });- broadcastId: The broadcast's numeric id (required)
- actionId: The action's numeric id (required)
- options: Object (optional) —
period,steps,unique
Get delivery metrics for a broadcast over time.
api.getBroadcastMetrics(4, { period: "days", steps: 30, type: "email" });- broadcastId: The broadcast's numeric id (required)
- options: Object (optional) —
period,steps,type
Get link (click) metrics for a broadcast over time.
api.getBroadcastMetricsLinks(4, { period: "days", steps: 30, unique: true });- broadcastId: The broadcast's numeric id (required)
- options: Object (optional) —
period,steps,unique
Get the individual messages (deliveries) sent by a broadcast.
api.getBroadcastMessages(4, { metric: "delivered", type: "email", limit: 50 });- broadcastId: The broadcast's numeric id (required)
- options: Object (optional) —
start,limit,metric,type,start_ts,end_ts,get_tracked_responses
List the API triggers fired for a broadcast.
api.getBroadcastTriggers(4);- broadcastId: The broadcast's numeric id (required)
List the newsletters in your workspace.
api.listNewsletters({ limit: 25, sort: "desc" });- options: Object (optional) —
start,limit,sort("asc" / "desc")
Create a newsletter. Both name and recipients (an audience filter) are required.
api.createNewsletter({
name: "Weekly digest",
recipients: { segment: { id: 7 } },
});- data: The newsletter definition
- name: The newsletter's name, ≤190 characters (required)
- recipients: An audience filter selecting who receives the newsletter (required)
- Additional fields may be required depending on configuration (e.g. channel-specific
subject/body, orsubscription_topic_idwhen the subscription center is enabled)
Get a single newsletter's metadata.
api.getNewsletter(8);- newsletterId: The newsletter's numeric id (required)
Delete a newsletter.
api.deleteNewsletter(8);- newsletterId: The newsletter's numeric id (required)
List all content variants of a newsletter.
api.getNewsletterContents(8);- newsletterId: The newsletter's numeric id (required)
Get a single content variant of a newsletter.
api.getNewsletterContent(8, 3);- newsletterId: The newsletter's numeric id (required)
- contentId: The content variant's numeric id (required)
Update a content variant of a newsletter.
api.updateNewsletterContent(8, 3, { subject: "Updated subject" });- newsletterId: The newsletter's numeric id (required)
- contentId: The content variant's numeric id (required)
- data: The content fields to update
Get metrics for a single newsletter content variant over time.
api.getNewsletterContentMetrics(8, 3, { period: "days", steps: 7 });- newsletterId: The newsletter's numeric id (required)
- contentId: The content variant's numeric id (required)
- options: Object (optional) —
period,steps(newsletter metrics are always aggregated across all channels)
Get link (click) metrics for a single newsletter content variant over time.
api.getNewsletterContentMetricsLinks(8, 3, { period: "weeks", steps: 4, unique: true });- newsletterId: The newsletter's numeric id (required)
- contentId: The content variant's numeric id (required)
- options: Object (optional) —
period,steps,unique
Get delivery metrics for a newsletter over time.
api.getNewsletterMetrics(8, { period: "days", steps: 30 });- newsletterId: The newsletter's numeric id (required)
- options: Object (optional) —
period,steps(newsletter metrics are always aggregated across all channels)
Get link (click) metrics for a newsletter over time.
api.getNewsletterMetricsLinks(8, { period: "days", steps: 30, unique: true });- newsletterId: The newsletter's numeric id (required)
- options: Object (optional) —
period,steps,unique
Get the individual messages (deliveries) sent by a newsletter.
api.getNewsletterMessages(8, { metric: "delivered", limit: 50 });- newsletterId: The newsletter's numeric id (required)
- options: Object (optional) —
start,limit,metric,type("email" / "webhook" / "twilio" / "push" / "in_app" / "inbox"),start_ts,end_ts,get_tracked_responses
Send a newsletter.
api.sendNewsletter(8, { rate_limit_email_rate: 100, rate_limit_time_period: 60 });- newsletterId: The newsletter's numeric id (required)
- data: Optional send settings —
rate_limit_email_rate,rate_limit_time_period,rate_limit_spread
Schedule a newsletter to send later. scheduled_at (a Unix timestamp) and timezone are both required.
api.scheduleNewsletter(8, { scheduled_at: 1719792000, timezone: "America/New_York" });- newsletterId: The newsletter's numeric id (required)
- data: The schedule settings
- scheduled_at: Unix timestamp (seconds) when the newsletter should send (required, must be in the future)
- timezone: IANA timezone the scheduled time is expressed in (required)
- Optional:
tz_match_enabled,rate_limit_email_rate,rate_limit_time_period,rate_limit_spread
Add a language (translation) to a newsletter. language is required, and the required content fields depend on the newsletter's channel (e.g. an email newsletter requires subject and body).
api.createNewsletterLanguage(8, { language: "fr", subject: "Bonjour", body: "<p>Bonjour !</p>" });- newsletterId: The newsletter's numeric id (required)
- data: The translation content
- language: The IETF language tag (required)
- subject / body: Required for email; other channels require their own fields (e.g.
body_jsonfor in-app/inbox,bodyfor SMS/webhook)
Get a single-language translation of a newsletter.
api.getNewsletterLanguage(8, "en-US");- newsletterId: The newsletter's numeric id (required)
- language: The IETF language tag (required)
Update a single-language translation of a newsletter.
api.updateNewsletterLanguage(8, "fr", { subject: "Salut" });- newsletterId: The newsletter's numeric id (required)
- language: The IETF language tag (required)
- data: The translation fields to update
Delete a single-language translation of a newsletter.
api.deleteNewsletterLanguage(8, "fr");- newsletterId: The newsletter's numeric id (required)
- language: The IETF language tag (required)
List a newsletter's A/B test groups.
api.getNewsletterTestGroups(8);- newsletterId: The newsletter's numeric id (required)
Create an A/B test group on a newsletter. The API takes no request body — a new empty test group is created.
api.createNewsletterTestGroup(8);- newsletterId: The newsletter's numeric id (required)
Add a language (translation) to a newsletter test group. Same content requirements as createNewsletterLanguage (language required, plus channel-specific fields such as subject/body for email).
api.createNewsletterTestGroupLanguage(8, 2, { language: "fr", subject: "Bonjour", body: "<p>Bonjour !</p>" });- newsletterId: The newsletter's numeric id (required)
- testGroupId: The test group's id (required)
- data: The translation content (
languagerequired; channel-specific content fields required)
Get a single-language translation of a newsletter test group.
api.getNewsletterTestGroupLanguage(8, 2, "en-US");- newsletterId: The newsletter's numeric id (required)
- testGroupId: The test group's id (required)
- language: The IETF language tag (required)
Update a single-language translation of a newsletter test group.
api.updateNewsletterTestGroupLanguage(8, 2, "fr", { subject: "Salut" });- newsletterId: The newsletter's numeric id (required)
- testGroupId: The test group's id (required)
- language: The IETF language tag (required)
- data: The translation fields to update
Delete a single-language translation of a newsletter test group.
api.deleteNewsletterTestGroupLanguage(8, 2, "fr");- newsletterId: The newsletter's numeric id (required)
- testGroupId: The test group's id (required)
- language: The IETF language tag (required)
Manage Design Studio folders and emails. Folders and emails are "nodes" identified by a UUID.
The list endpoints share a common set of filters, sorting, and page-based pagination (they do not use the cursor pagination of the other App API list endpoints):
- parentFolderId: Only list nodes directly within this folder (omit for the root)
- directDescendantsOnly: When
true, return only direct children rather than the whole subtree - sortBy:
"created"/"updated"/"name"(default"created") - sortOrder:
"asc"/"desc"(default"asc") - createdBefore / createdAfter / updatedBefore / updatedAfter: Unix timestamps (seconds)
- page: 1-based page number (default 1)
- limit: page size, 1–10000 (default 1000)
In folder and email bodies, parent_folder_id is tri-state: omit it to keep the current parent, pass null to move to the root, or pass a folder UUID to move it into that folder.
List Design Studio folders.
api.listDesignStudioFolders({ parentFolderId: "1f0…", directDescendantsOnly: true, limit: 50 });- options: Object (optional) — the shared list filters described above
Create a folder.
api.createDesignStudioFolder({ name: "Campaigns", parent_folder_id: null });- folder: The folder definition
- name: The folder's display name (required)
- parent_folder_id: Parent folder UUID, or
null/omit for the root
Get a single folder.
api.getDesignStudioFolder("1f0…");- folderId: The folder's UUID (required)
Update a folder. At least one field must be provided. Returns no content on success.
api.updateDesignStudioFolder("1f0…", { name: "Renamed", parent_folder_id: null });- folderId: The folder's UUID (required)
- updates: Object with any of
name,parent_folder_id
Delete a folder. Returns no content on success.
api.deleteDesignStudioFolder("1f0…");- folderId: The folder's UUID (required)
List Design Studio emails. In addition to the shared list filters, emails support three tri-state filters — each "true", "false", or "any" (no filter).
api.listDesignStudioEmails({ isTemplate: "true", hasTranslations: "any", limit: 25 });- options: Object (optional) — the shared list filters, plus:
- isTemplate:
"true"/"false"/"any" - hasTranslations:
"true"/"false"/"any" - isLinked:
"true"/"false"/"any"(whether the email is linked to a message)
- isTemplate:
Create an email.
api.createDesignStudioEmail({
name: "Welcome",
is_template: false,
content: { subject: "Welcome!", html: "<p>Hi {{customer.first_name}}</p>" },
envelope: { recipient: "{{customer.email}}" },
});- email: The email definition
- name: The email's display name (required)
- parent_folder_id: Parent folder UUID, or
null/omit for the root - is_template: Whether the email is a reusable template
- content:
{ subject, preheader_text, html, amp, text } - envelope:
{ from_id, reply_to_id, recipient, bcc, fake_bcc, cc, headers } - transformers: Content transformers (e.g.
url_parameters,css_inliner,accessibility)
Get a single email.
api.getDesignStudioEmail("2a1…");- emailId: The email's UUID (required)
Update an email. At least one field must be provided. Returns no content on success.
api.updateDesignStudioEmail("2a1…", { is_template: true, content: { subject: "Updated" } });- emailId: The email's UUID (required)
- updates: Object with any of
name,parent_folder_id,is_template,content,envelope,transformers
Delete an email. Returns no content on success.
api.deleteDesignStudioEmail("2a1…");- emailId: The email's UUID (required)
List the translations (languages) of an email.
api.listDesignStudioEmailLanguages("2a1…");- emailId: The email's UUID (required)
Create a translation of an email. Content blocks you omit are inherited from the default-language email.
api.createDesignStudioEmailLanguage("2a1…", {
language: "fr",
content: { subject: "Bonjour" },
});- emailId: The email's UUID (required)
- translation: The translation definition
- language: IETF language tag (required)
- content:
{ subject, preheader_text, html, amp, text } - envelope:
{ from_id, reply_to_id, recipient, bcc, fake_bcc, cc, headers } - transformers: Content transformers
Get a single-language translation of an email.
api.getDesignStudioEmailLanguage("2a1…", "fr");- emailId: The email's UUID (required)
- language: The IETF language tag (required)
Update a translation. At least one field must be provided. The language itself is immutable. Returns no content on success.
api.updateDesignStudioEmailLanguage("2a1…", "fr", { content: { subject: "Salut" } });- emailId: The email's UUID (required)
- language: The IETF language tag (required)
- updates: Object with any of
content,envelope,transformers
Delete a translation. Returns no content on success.
api.deleteDesignStudioEmailLanguage("2a1…", "fr");- emailId: The email's UUID (required)
- language: The IETF language tag (required)
List Design Studio components.
api.listDesignStudioComponents({ tag: "header", limit: 25 });- options: Object (optional) — the shared list filters described above, plus:
- tag: Only list components with this tag
Create a component.
api.createDesignStudioComponent({ name: "Header", tag: "header", content: "<div>…</div>" });- component: The component definition
- name: The component's display name (required)
- tag: The component's tag, unique per workspace (required)
- parent_folder_id: Parent folder UUID, or
null/omit for the root - content: The component's HTML content
Get a single component.
api.getDesignStudioComponent("3b2…");- componentId: The component's UUID (required)
Update a component. At least one field must be provided. Returns no content on success.
api.updateDesignStudioComponent("3b2…", { content: "<div>updated</div>" });- componentId: The component's UUID (required)
- updates: Object with any of
name,tag,parent_folder_id,content
Delete a component. Returns no content on success.
api.deleteDesignStudioComponent("3b2…");- componentId: The component's UUID (required)
Manage uploaded files (images, PDFs) and the folders that organize them. Asset and folder ids are integers.
The list endpoints share folder filtering and page-based pagination:
- parentFolderId: Only list items within this folder id (omit for all/root)
- directDescendantsOnly: When
true, return only direct children rather than the whole subtree - page: 1-based page number (default 1)
- limit: page size, 1–10000 (default 1000)
On file and folder updates, parent_folder_id is tri-state: omit to keep the current parent, pass null to move to the root, or pass a folder id to move it.
List uploaded files.
api.listAssets({ parentFolderId: 5, limit: 50 });- options: Object (optional) —
parentFolderId,directDescendantsOnly,page,limit
Upload a file (multipart/form-data). The API accepts images (image/bmp, image/jpeg, image/jpg, image/png, image/gif) and application/pdf, up to 2 MB (images max 4096px per side).
const fs = require("fs");
api.createAsset({
data: fs.readFileSync("logo.png"),
filename: "logo.png",
contentType: "image/png",
parentFolderId: 5,
});- file: The upload definition
- data: File contents — any
Buffer/Blob-compatible value (required) - filename: Filename; also the default asset name and, when
contentTypeis omitted, the source for the derived content type (required) - contentType: MIME type of the upload; when omitted the SDK derives it from the filename extension (
.bmp,.jpg/.jpeg,.png,.gif,.pdf) - name: Asset name; defaults to
filename - parentFolderId: Parent folder id; omit for the root
- data: File contents — any
Get a single file.
api.getAsset(42);- assetId: The asset's numeric id (required)
Rename and/or move a file. At least one field must be provided; the file bytes cannot be changed. Returns no content on success.
api.updateAsset(42, { name: "renamed.png", parent_folder_id: null });- assetId: The asset's numeric id (required)
- updates: Object with any of
name,parent_folder_id
Delete a file. Returns no content on success.
api.deleteAsset(42);- assetId: The asset's numeric id (required)
List asset folders.
api.listAssetFolders({ parentFolderId: 5, limit: 50 });- options: Object (optional) —
parentFolderId,directDescendantsOnly,page,limit
Create an asset folder.
api.createAssetFolder({ name: "Product images", parent_folder_id: 5 });- folder: The folder definition
- name: The folder's display name (required)
- parent_folder_id: Parent folder id; omit for the root
Get a single asset folder.
api.getAssetFolder(5);- folderId: The folder's numeric id (required)
Rename and/or move a folder. At least one field must be provided. Returns no content on success.
api.updateAssetFolder(5, { name: "Renamed", parent_folder_id: null });- folderId: The folder's numeric id (required)
- updates: Object with any of
name,parent_folder_id
Delete an asset folder. The folder must be empty.
api.deleteAssetFolder(5);- folderId: The folder's numeric id (required)
Manage data collections — reusable datasets you can reference from messages. Collection ids are integers.
List the collections in your workspace.
api.listCollections();Create a collection. Provide inline data or a source url, not both.
api.createCollection({
name: "Plans",
data: [
{ tier: "free", price: 0 },
{ tier: "pro", price: 20 },
],
});- collection: The collection definition
- name: The collection's name (required)
- data: An array of row objects (mutually exclusive with
url) - url: A source URL to import rows from — CSV/JSON/Google Sheet (mutually exclusive with
data)
Get a single collection's metadata (name, schema, rows, bytes, timestamps). Use getCollectionContent for the rows themselves.
api.getCollection(9);- collectionId: The collection's numeric id (required)
Update a collection. Any subset of fields may be provided; data and url are mutually exclusive.
api.updateCollection(9, { name: "Renamed" });- collectionId: The collection's numeric id (required)
- updates: Object with any of
name,data,url
Delete a collection. Returns no content on success. Fails if the collection is still referenced by a campaign.
api.deleteCollection(9);- collectionId: The collection's numeric id (required)
Get a collection's content — the full array of data rows.
api.getCollectionContent(9);- collectionId: The collection's numeric id (required)
Replace a collection's content with a new array of data rows.
api.updateCollectionContent(9, [
{ tier: "free", price: 0 },
{ tier: "pro", price: 20 },
]);- collectionId: The collection's numeric id (required)
- content: An array of row objects (required)
Manage the email-provider suppression lists. suppressionType is one of "blocks", "bounces", "spam_reports", or "invalid_emails".
Search every suppression category for an email address.
api.searchSuppression("person@example.com");- email: The email address to search for (required)
List suppressions in a category (offset-based pagination).
api.getSuppressions("bounces", { limit: 50, offset: 0 });- suppressionType: One of
"blocks"/"bounces"/"spam_reports"/"invalid_emails"(required) - options: Object (optional) —
limit(1–1000, default 100),offset(default 0),email,domain
List suppressions in a category for a single sending domain (cursor-based pagination — preferred for large volumes).
api.getDomainSuppressions("mail.example.com", "bounces", { limit: 100, start: cursor });- domainName: The sending domain (required)
- suppressionType: One of
"blocks"/"bounces"/"spam_reports"/"invalid_emails"(required) - options: Object (optional) —
limit(1–1000, default 100),email,start(pagination cursor from a previous page'snext)
Add an email address to a suppression category.
api.createSuppression("bounces", "person@example.com");- suppressionType: One of
"blocks"/"bounces"/"spam_reports"/"invalid_emails"(required) - email: The email address to suppress (required)
Remove an email address from a suppression category. Returns no content on success.
api.deleteSuppression("bounces", "person@example.com");- suppressionType: One of
"blocks"/"bounces"/"spam_reports"/"invalid_emails"(required) - email: The email address to unsuppress (required)
Manage reporting webhooks that POST message events to your endpoint. Webhook ids are integers.
List the reporting webhooks in your workspace.
api.listReportingWebhooks();Create a reporting webhook.
api.createReportingWebhook({
endpoint: "https://example.com/cio-events",
events: ["sent", "delivered", "opened", "clicked", "bounced"],
name: "Production events",
with_content: false,
});- webhook: The webhook definition
- endpoint: The destination URL that events are POSTed to (required)
- events: The event types to send (e.g.
drafted,sent,delivered,opened,clicked,bounced,converted) - name: Display name, ≤190 characters
- full_resolution: Send an event for every occurrence rather than de-duplicating
- with_content: Include message content in the payloads
- disabled: Create the webhook in a disabled state
Get a single reporting webhook.
api.getReportingWebhook(4);- webhookId: The webhook's numeric id (required)
Update a reporting webhook. Any subset of fields may be provided.
api.updateReportingWebhook(4, { disabled: true });- webhookId: The webhook's numeric id (required)
- updates: Object with any of
endpoint,events,name,full_resolution,with_content,disabled
Delete a reporting webhook. Returns no content on success.
api.deleteReportingWebhook(4);- webhookId: The webhook's numeric id (required)
Manage snippets — reusable content blocks referenced from messages. Snippets are identified by name.
List the snippets in your workspace.
api.getSnippets();Create a snippet.
api.createSnippet({ name: "footer", value: "<p>© 2026 Example</p>" });- snippet: The snippet definition
- name: The snippet's unique name/key (required)
- value: The snippet's value; may contain Liquid (required)
Create or update a snippet (upsert by name).
api.updateSnippet({ name: "footer", value: "<p>© 2027 Example</p>" });- snippet: The snippet definition —
nameandvalue(both required)
Delete a snippet by name. Returns no content on success. Fails if the snippet is still in use.
api.deleteSnippet("footer");- name: The snippet's name (required)
List the sender identities in your workspace.
api.getSenderIdentities({ limit: 50, sort: "asc" });- options: Object (optional) —
start,limit,sort("asc" / "desc"),hidden(omit for all,true/falseto filter)
Get a single sender identity.
api.getSenderIdentity(12);- senderId: The sender identity's numeric id (required)
List the campaigns and newsletters that use a sender identity.
api.getSenderIdentityUsedBy(12);- senderId: The sender identity's numeric id (required)
Look up sent messages (deliveries) across your workspace. For a single person's messages, use getCustomerMessages.
List sent messages.
api.getMessages({ metric: "delivered", type: "email", limit: 50 });- options: Object (optional)
- start: Pagination cursor from a previous page's
next - limit: Maximum number of results
- drafts: Return only drafts (
true) or exclude them (default) - metric: Filter to a delivery metric (e.g.
delivered,opened,bounced) - type: Scope to a channel ("email" / "webhook" / "twilio" / "whatsapp" / "slack" / "push" / "in_app")
- campaign_id / action_id / newsletter_id / transactional_id / trigger_id / template_id / content_id: Scope to a single resource
- start_ts / end_ts: Unix timestamp bounds (seconds)
- associations: Include related campaigns/actions/newsletters/contents
- get_tracked_responses: Include tracked responses on each delivery
- start: Pagination cursor from a previous page's
Get a single sent message.
api.getMessage("RPCImftJDcAAAAd...", { archived_message: true });- messageId: The delivery id (
CIO-Delivery-ID) (required) - options: Object (optional) —
archived_message,associations,get_tracked_responses
Get the archived content of a single sent message.
api.getArchivedMessage("RPCImftJDcAAAAd...");- messageId: The delivery id (
CIO-Delivery-ID) (required)
Start a CSV import. The CSV is loaded from a hosted URL you provide as data_file_url.
api.createImport({
data_file_url: "https://example.com/people.csv",
type: "people",
identifier: "email",
name: "Q3 signups",
});- importData: The import definition
- data_file_url: URL of the CSV file to import (required)
- type:
"people"/"event"/"object"/"relationship"(required) - identifier: Which column keys the rows —
"id"/"email"for people & events;"id"/"email"/"cio_id"for relationships - object_type_id: Required when
typeis"object" - name: Display name (defaults to the filename)
- description: Description of the import
- people_to_process / data_to_process:
"all"/"only_existing"/"only_new"(mutually exclusive)
Get the status of an import.
api.getImport(15);- importId: The import's numeric id (required)
Batch-update attribute metadata (descriptions, etc.) — up to 100 at a time.
api.batchUpdateAttributes([{ name: "plan", description: "Subscription plan" }]);- attributes: A non-empty array of attribute updates (max 100). Each requires a
name; may also includedescription,object_type_id,is_relationship,event_name,privacy_level
Batch-update event metadata — up to 100 at a time.
api.batchUpdateEvents([{ name: "purchase", description: "Completed a purchase" }]);- events: A non-empty array of event updates (max 100). Each requires a
name; may also includedescription
List the workspaces (environments) in your account, with usage counts.
api.listWorkspaces();List the Customer.io egress IP addresses (for allowlisting).
api.getIpAddresses();