diff --git a/README.md b/README.md index 192fb3f..ca267c5 100644 --- a/README.md +++ b/README.md @@ -109,7 +109,13 @@ You can use custom contact properties in API calls. Please make sure to [add cus - [updateTransactionalEmail()](#updatetransactionalemail) - [ensureTransactionalEmailDraft()](#ensuretransactionalemaildraft) - [publishTransactionalEmail()](#publishtransactionalemail) +- [listTransactionalGroups()](#listtransactionalgroups) +- [createTransactionalGroup()](#createtransactionalgroup) +- [getTransactionalGroup()](#gettransactionalgroup) +- [updateTransactionalGroup()](#updatetransactionalgroup) - [listDedicatedSendingIps()](#listdedicatedsendingips) +- [listAudienceSegments()](#listaudiencesegments) +- [getAudienceSegment()](#getaudiencesegment) - [listThemes()](#listthemes) - [getTheme()](#gettheme) - [listComponents()](#listcomponents) @@ -118,8 +124,16 @@ You can use custom contact properties in API calls. Please make sure to [add cus - [createCampaign()](#createcampaign) - [getCampaign()](#getcampaign) - [updateCampaign()](#updatecampaign) +- [listCampaignGroups()](#listcampaigngroups) +- [createCampaignGroup()](#createcampaigngroup) +- [getCampaignGroup()](#getcampaigngroup) +- [updateCampaignGroup()](#updatecampaigngroup) - [getEmailMessage()](#getemailmessage) - [updateEmailMessage()](#updateemailmessage) +- [sendEmailMessagePreview()](#sendemailmessagepreview) +- [listWorkflows()](#listworkflows) +- [getWorkflow()](#getworkflow) +- [getWorkflowNode()](#getworkflownode) - [createUpload()](#createupload) - [completeUpload()](#completeupload) @@ -200,7 +214,7 @@ const resp = await loops.createContact({ ```json { "success": true, - "id": "id_of_contact" + "id": "clw9h3y5a014yl70k9m2n4p8q" } ``` @@ -264,7 +278,7 @@ const resp = await loops.updateContact({ ```json { "success": true, - "id": "id_of_contact" + "id": "clw9h3y5a014yl70k9m2n4p8q" } ``` @@ -880,7 +894,8 @@ const resp = await loops.listTransactionalEmails({ perPage: 15 }); "id": "clfn0k1yg001imo0fdeqg30i8", "name": "Sign up confirmation", "draftEmailMessageId": null, - "publishedEmailMessageId": "msg_123", + "publishedEmailMessageId": "clm9x3o5q002yl70a8b3c4d5e", + "transactionalGroupId": null, "createdAt": "2023-11-06T17:48:07.249Z", "updatedAt": "2023-11-06T17:48:07.249Z", "dataVariables": [] @@ -888,8 +903,9 @@ const resp = await loops.listTransactionalEmails({ perPage: 15 }); { "id": "cll42l54f20i1la0lfooe3z12", "name": "Password reset", - "draftEmailMessageId": "msg_456", - "publishedEmailMessageId": "msg_789", + "draftEmailMessageId": "clm8k2n4p000yl70f6g7h8i9j", + "publishedEmailMessageId": "clm8k2n4p001yl70k1l2m3n4o", + "transactionalGroupId": "clq3b7s9u006yl70p5q6r7s8t", "createdAt": "2025-02-02T02:56:28.845Z", "updatedAt": "2025-02-02T02:56:28.845Z", "dataVariables": [ @@ -911,14 +927,14 @@ Retrieve a single transactional email by ID. #### Parameters -| Name | Type | Required | Notes | -| ----------------- | ------ | -------- | ------------------------------------ | -| `transactionalId` | string | Yes | The ID of the transactional email. | +| Name | Type | Required | Notes | +| --------------------- | ------ | -------- | ------------------------------------ | +| `transactionalId` | string | Yes | The ID of the transactional email. | #### Example ```javascript -const resp = await loops.getTransactionalEmail("trans_123"); +const resp = await loops.getTransactionalEmail("clfn0k1yg001imo0fdeqg30i8"); ``` --- @@ -931,9 +947,10 @@ Create a new transactional email. An empty draft email message is created automa #### Parameters -| Name | Type | Required | Notes | -| ------ | ------ | -------- | ---------------------------------- | -| `name` | string | Yes | The name of the transactional email. | +| Name | Type | Required | Notes | +| --------------------- | ------ | -------- | ---------------------------------------------------------------------------------------- | +| `name` | string | Yes | The name of the transactional email. | +| `transactionalGroupId`| string | No | The ID of the group to add this transactional email to. Defaults to the team's default group. | #### Example @@ -945,23 +962,28 @@ const resp = await loops.createTransactionalEmail({ name: "Welcome email" }); ### updateTransactionalEmail() -Update a transactional email by ID. +Update a transactional email by ID. At least one field is required. [API Reference](https://loops.so/docs/api-reference/update-transactional-email) #### Parameters -| Name | Type | Required | Notes | -| ----------------- | ------ | -------- | ---------------------------------- | -| `transactionalId` | string | Yes | The ID of the transactional email. | -| `name` | string | Yes | The name of the transactional email. | +| Name | Type | Required | Notes | +| --------------------- | ------ | -------- | -------------------------------------------------------- | +| `transactionalId` | string | Yes | The ID of the transactional email. | +| `name` | string | No | The name of the transactional email. | +| `transactionalGroupId`| string | No | The ID of the group to move this transactional email to. | #### Example ```javascript -const resp = await loops.updateTransactionalEmail("trans_123", { +const resp = await loops.updateTransactionalEmail("clfn0k1yg001imo0fdeqg30i8", { name: "Updated name", }); + +const resp = await loops.updateTransactionalEmail("clfn0k1yg001imo0fdeqg30i8", { + transactionalGroupId: "clq3b7s9u006yl70p5q6r7s8t", +}); ``` --- @@ -974,14 +996,14 @@ Ensure a transactional email has a draft email message. Use [`updateEmailMessage #### Parameters -| Name | Type | Required | Notes | -| ----------------- | ------ | -------- | ---------------------------------- | +| Name | Type | Required | Notes | +| ---- | ------ | -------- | ---------------------------------- | | `transactionalId` | string | Yes | The ID of the transactional email. | #### Example ```javascript -const resp = await loops.ensureTransactionalEmailDraft("trans_123"); +const resp = await loops.ensureTransactionalEmailDraft("clfn0k1yg001imo0fdeqg30i8"); ``` --- @@ -994,14 +1016,14 @@ Publish a transactional email's current draft. #### Parameters -| Name | Type | Required | Notes | -| ----------------- | ------ | -------- | ---------------------------------- | +| Name | Type | Required | Notes | +| ---- | ------ | -------- | ---------------------------------- | | `transactionalId` | string | Yes | The ID of the transactional email. | #### Example ```javascript -const resp = await loops.publishTransactionalEmail("trans_123"); +const resp = await loops.publishTransactionalEmail("clfn0k1yg001imo0fdeqg30i8"); ``` --- @@ -1037,8 +1059,7 @@ Error handling is done through the `APIError` class, which provides `statusCode` ### listThemes() -Retrieve a paginated list of email themes, most recently created first. Requires the content API to be enabled for your team. - +Retrieve a paginated list of email themes, most recently created first. [API Reference](https://loops.so/docs/api-reference/list-themes) #### Parameters @@ -1060,7 +1081,6 @@ const resp = await loops.listThemes({ perPage: 15, cursor: "clyo0q4wo01p59fsecyx ```json { - "success": true, "pagination": { "totalResults": 1, "returnedResults": 1, @@ -1071,7 +1091,7 @@ const resp = await loops.listThemes({ perPage: 15, cursor: "clyo0q4wo01p59fsecyx }, "data": [ { - "themeId": "theme_123", + "id": "clo1z5q7s004yl70y3z4a5b6c", "name": "Default", "styles": { "backgroundColor": "#ffffff" @@ -1090,28 +1110,26 @@ Error handling is done through the `APIError` class, which provides `statusCode` ### getTheme() -Retrieve a single theme by ID. Requires the content API to be enabled for your team. - +Retrieve a single theme by ID. [API Reference](https://loops.so/docs/api-reference/get-theme) #### Parameters -| Name | Type | Required | Notes | -| --------- | ------ | -------- | -------------------- | +| Name | Type | Required | Notes | +| ---- | ------ | -------- | -------------------- | | `themeId` | string | Yes | The ID of the theme. | #### Example ```javascript -const resp = await loops.getTheme("theme_123"); +const resp = await loops.getTheme("clo1z5q7s004yl70y3z4a5b6c"); ``` #### Response ```json { - "success": true, - "themeId": "theme_123", + "id": "clo1z5q7s004yl70y3z4a5b6c", "name": "Default", "styles": { "backgroundColor": "#ffffff" @@ -1128,8 +1146,7 @@ Error handling is done through the `APIError` class, which provides `statusCode` ### listComponents() -Retrieve a paginated list of email components. Requires the content API to be enabled for your team. - +Retrieve a paginated list of email components. [API Reference](https://loops.so/docs/api-reference/list-components) #### Parameters @@ -1151,7 +1168,6 @@ const resp = await loops.listComponents({ perPage: 15 }); ```json { - "success": true, "pagination": { "totalResults": 1, "returnedResults": 1, @@ -1162,7 +1178,7 @@ const resp = await loops.listComponents({ perPage: 15 }); }, "data": [ { - "componentId": "comp_123", + "id": "clp2a6r8t005yl70d7e8f9g0h", "name": "Header", "lmx": "
...
" } @@ -1176,28 +1192,26 @@ Error handling is done through the `APIError` class, which provides `statusCode` ### getComponent() -Retrieve a single component by ID. Requires the content API to be enabled for your team. - +Retrieve a single component by ID. [API Reference](https://loops.so/docs/api-reference/get-component) #### Parameters -| Name | Type | Required | Notes | -| ------------- | ------ | -------- | ------------------------- | +| Name | Type | Required | Notes | +| ---- | ------ | -------- | ------------------------- | | `componentId` | string | Yes | The ID of the component. | #### Example ```javascript -const resp = await loops.getComponent("comp_123"); +const resp = await loops.getComponent("clp2a6r8t005yl70d7e8f9g0h"); ``` #### Response ```json { - "success": true, - "componentId": "comp_123", + "id": "clp2a6r8t005yl70d7e8f9g0h", "name": "Header", "lmx": "
...
" } @@ -1209,8 +1223,7 @@ Error handling is done through the `APIError` class, which provides `statusCode` ### listCampaigns() -Retrieve a paginated list of campaigns. Requires the content API to be enabled for your team. - +Retrieve a paginated list of campaigns. [API Reference](https://loops.so/docs/api-reference/list-campaigns) #### Parameters @@ -1232,7 +1245,6 @@ const resp = await loops.listCampaigns({ perPage: 15 }); ```json { - "success": true, "pagination": { "totalResults": 1, "returnedResults": 1, @@ -1243,13 +1255,20 @@ const resp = await loops.listCampaigns({ perPage: 15 }); }, "data": [ { - "campaignId": "camp_123", - "emailMessageId": "msg_123", + "id": "cln0y4p6r003yl70i1j2k3l4m", + "emailMessageId": "clm9x3o5q002yl70a8b3c4d5e", "name": "Spring announcement", - "subject": "", "status": "Draft", "createdAt": "2025-01-01T00:00:00.000Z", - "updatedAt": "2025-01-01T00:00:00.000Z" + "updatedAt": "2025-01-01T00:00:00.000Z", + "campaignGroupId": null, + "mailingListId": null, + "audienceSegmentId": null, + "audienceFilter": null, + "scheduling": { + "method": "now", + "timestamp": null + } } ] } @@ -1261,34 +1280,51 @@ Error handling is done through the `APIError` class, which provides `statusCode` ### createCampaign() -Create a new draft campaign. An empty email message is created automatically and its `emailMessageId` is returned. Use [`updateEmailMessage()`](#updateemailmessage) to set subject, sender, preview text, and LMX content. Requires the content API to be enabled for your team. - +Create a new draft campaign. An empty email message is created automatically and its `emailMessageId` is returned. Use [`updateEmailMessage()`](#updateemailmessage) to set subject, sender, preview text, and LMX content. The audience (mailing list, segment, or filter), group, and scheduling can be set on create or later via update. [API Reference](https://loops.so/docs/api-reference/create-campaign) #### Parameters -| Name | Type | Required | Notes | -| ------ | ------ | -------- | ------------------ | -| `name` | string | Yes | The campaign name. | +| Name | Type | Required | Notes | +| ------------------- | ------- | -------- | ---------------------------------------------------------------------------------------- | +| `name` | string | Yes | The campaign name. | +| `campaignGroupId` | string | No | The ID of the group to add this campaign to. | +| `mailingListId` | string | No | The ID of the mailing list to send to. | +| `audienceSegmentId` | string | No | The ID of an audience segment. Setting this clears any `audienceFilter`. | +| `audienceFilter` | object | No | An audience filter object. See the [API reference](https://loops.so/docs/api-reference/create-campaign). | +| `scheduling` | object | No | When the campaign should send (`method`: `now` or `schedule`, with optional `timestamp`). | #### Example ```javascript const resp = await loops.createCampaign({ name: "Spring announcement" }); + +const resp = await loops.createCampaign({ + name: "Spring announcement", + mailingListId: "cm06f5v0e45nf0ml5754o9cix", + scheduling: { method: "schedule", timestamp: "2026-06-15T10:00:00.000Z" }, +}); ``` #### Response ```json { - "success": true, - "campaignId": "camp_123", + "id": "cln0y4p6r003yl70i1j2k3l4m", "name": "Spring announcement", "status": "Draft", "createdAt": "2025-01-01T00:00:00.000Z", "updatedAt": "2025-01-01T00:00:00.000Z", - "emailMessageId": "msg_123", - "emailMessageContentRevisionId": "rev_123" + "emailMessageId": "clm9x3o5q002yl70a8b3c4d5e", + "emailMessageContentRevisionId": "clv8g2x4z012yl70n5o6p7q8r", + "campaignGroupId": null, + "mailingListId": null, + "audienceSegmentId": null, + "audienceFilter": null, + "scheduling": { + "method": "now", + "timestamp": null + } } ``` @@ -1298,33 +1334,39 @@ Error handling is done through the `APIError` class, which provides `statusCode` ### getCampaign() -Retrieve a single campaign by ID. Requires the content API to be enabled for your team. - +Retrieve a single campaign by ID. [API Reference](https://loops.so/docs/api-reference/get-campaign) #### Parameters -| Name | Type | Required | Notes | -| ------------ | ------ | -------- | ----------------------- | +| Name | Type | Required | Notes | +| ---- | ------ | -------- | ----------------------- | | `campaignId` | string | Yes | The ID of the campaign. | #### Example ```javascript -const resp = await loops.getCampaign("camp_123"); +const resp = await loops.getCampaign("cln0y4p6r003yl70i1j2k3l4m"); ``` #### Response ```json { - "success": true, - "campaignId": "camp_123", + "id": "cln0y4p6r003yl70i1j2k3l4m", "name": "Spring announcement", "status": "Draft", "createdAt": "2025-01-01T00:00:00.000Z", "updatedAt": "2025-01-01T00:00:00.000Z", - "emailMessageId": "msg_123" + "emailMessageId": "clm9x3o5q002yl70a8b3c4d5e", + "campaignGroupId": null, + "mailingListId": null, + "audienceSegmentId": null, + "audienceFilter": null, + "scheduling": { + "method": "now", + "timestamp": null + } } ``` @@ -1334,34 +1376,45 @@ Error handling is done through the `APIError` class, which provides `statusCode` ### updateCampaign() -Update a draft campaign's name. Campaigns can only be updated while in draft status. Requires the content API to be enabled for your team. - +Update a draft campaign's name, group, audience, or scheduling. At least one field must be provided. Campaigns can only be updated while in draft status. [API Reference](https://loops.so/docs/api-reference/update-campaign) #### Parameters -| Name | Type | Required | Notes | -| ------------ | ------ | -------- | ----------------------- | -| `campaignId` | string | Yes | The ID of the campaign. | -| `name` | string | Yes | The campaign name. | +| Name | Type | Required | Notes | +| ------------------- | ------ | -------- | ---------------------------------------------------------------------------------------- | +| `campaignId` | string | Yes | The ID of the campaign. | +| `name` | string | No | The campaign name. | +| `campaignGroupId` | string | No | The ID of the group to move this campaign to. | +| `mailingListId` | string | No | The ID of the mailing list to send to. | +| `audienceSegmentId` | string | No | The ID of an audience segment. Setting this clears any `audienceFilter`. | +| `audienceFilter` | object | No | An audience filter object. | +| `scheduling` | object | No | When the campaign should send. At least one field is required. | #### Example ```javascript -const resp = await loops.updateCampaign("camp_123", { name: "Updated name" }); +const resp = await loops.updateCampaign("cln0y4p6r003yl70i1j2k3l4m", { name: "Updated name" }); ``` #### Response ```json { - "success": true, - "campaignId": "camp_123", + "id": "cln0y4p6r003yl70i1j2k3l4m", "name": "Updated name", "status": "Draft", "createdAt": "2025-01-01T00:00:00.000Z", "updatedAt": "2025-01-02T00:00:00.000Z", - "emailMessageId": "msg_123" + "emailMessageId": "clm9x3o5q002yl70a8b3c4d5e", + "campaignGroupId": null, + "mailingListId": null, + "audienceSegmentId": null, + "audienceFilter": null, + "scheduling": { + "method": "now", + "timestamp": null + } } ``` @@ -1379,36 +1432,35 @@ HTTP 409 Conflict ### getEmailMessage() -Retrieve an email message, including its compiled LMX content. Requires the content API to be enabled for your team. - +Retrieve an email message, including its compiled LMX content. [API Reference](https://loops.so/docs/api-reference/get-email-message) #### Parameters -| Name | Type | Required | Notes | -| ----------------- | ------ | -------- | ---------------------------- | -| `emailMessageId` | string | Yes | The ID of the email message. | +| Name | Type | Required | Notes | +| ---- | ------ | -------- | ---------------------------- | +| `emailMessageId` | string | Yes | The ID of the email message. | #### Example ```javascript -const resp = await loops.getEmailMessage("msg_123"); +const resp = await loops.getEmailMessage("clm9x3o5q002yl70a8b3c4d5e"); ``` #### Response ```json { - "success": true, - "emailMessageId": "msg_123", - "campaignId": "camp_123", + "id": "clm9x3o5q002yl70a8b3c4d5e", + "campaignId": "cln0y4p6r003yl70i1j2k3l4m", "subject": "Hello", "previewText": "Preview text", "fromName": "Loops", "fromEmail": "hello", "replyToEmail": "", + "emailFormat": "styled", "lmx": "...", - "contentRevisionId": "rev_123", + "contentRevisionId": "clv8g2x4z012yl70n5o6p7q8r", "updatedAt": "2025-01-01T00:00:00.000Z" } ``` @@ -1419,28 +1471,34 @@ Error handling is done through the `APIError` class, which provides `statusCode` ### updateEmailMessage() -Update fields on an email message (subject, preview text, sender, LMX content). The campaign must be in draft status. Supply `expectedRevisionId` matching the current `contentRevisionId` — the server rejects mismatched revisions with 409. Requires the content API to be enabled for your team. - +Update fields on an email message (subject, preview text, sender, LMX content). The campaign must be in draft status. Supply `expectedRevisionId` matching the current `contentRevisionId` — the server rejects mismatched revisions with 409. [API Reference](https://loops.so/docs/api-reference/update-email-message) #### Parameters -| Name | Type | Required | Notes | -| ---------------------- | ------ | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | -| `emailMessageId` | string | Yes | The ID of the email message. | -| `expectedRevisionId` | string | No | The `contentRevisionId` you last fetched. Used for optimistic concurrency. | -| `subject` | string | No | The email subject. | -| `previewText` | string | No | The email preview text. | -| `fromName` | string | No | The sender name. | -| `fromEmail` | string | No | The sender username (without `@` or domain). The team's sending domain is appended automatically. | -| `replyToEmail` | string | No | Reply-to email. Must be empty or a valid email address. | -| `lmx` | string | No | The email body serialized as LMX. Styles must be embedded in the LMX `