diff --git a/README.md b/README.md index 0de6ec66e..157860d5a 100644 --- a/README.md +++ b/README.md @@ -127,7 +127,8 @@ This library currently supports a subset of the [Braze API endpoints](https://ww ### Subscription groups -- [ ] /subscription/status/set +- [x] /subscription/status/set +- [ ] /v2/subscription/status/set - [ ] /subscription/status/get - [ ] /subscription/user/status diff --git a/src/Braze.test.ts b/src/Braze.test.ts index 87357c8d1..3c253b3b2 100644 --- a/src/Braze.test.ts +++ b/src/Braze.test.ts @@ -12,6 +12,7 @@ import type { MessagesScheduleUpdateObject, MessagesSendObject, SendsIdCreateObject, + SubscriptionStatusSetObject, TransactionalV1CampaignsSendObject, UsersAliasObject, UsersDeleteObject, @@ -183,6 +184,13 @@ it('calls sends.id.create()', async () => { expect(mockedRequest).toBeCalledTimes(1) }) +it('calls subscription.status.set()', async () => { + mockedRequest.mockResolvedValueOnce(response) + expect(await braze.subscription.status.set(body as SubscriptionStatusSetObject)).toBe(response) + expect(mockedRequest).toBeCalledWith(`${apiUrl}/subscription/status/set`, body, options) + expect(mockedRequest).toBeCalledTimes(1) +}) + it('calls transactional.v1.campaigns.send()', async () => { mockedRequest.mockResolvedValueOnce(response) const campaignId = 'YOUR_CAMPAIGN_ID_HERE' diff --git a/src/Braze.ts b/src/Braze.ts index 4e3e26a02..9fa433522 100644 --- a/src/Braze.ts +++ b/src/Braze.ts @@ -2,6 +2,7 @@ import * as campaigns from './campaigns' import * as canvas from './canvas' import * as messages from './messages' import * as sends from './sends' +import * as subscription from './subscription' import * as transactional from './transactional' import * as users from './users' @@ -94,6 +95,13 @@ export class Braze { }, } + subscription = { + status: { + set: (body: subscription.status.SubscriptionStatusSetObject) => + subscription.status.set(this.apiUrl, this.apiKey, body), + }, + } + transactional = { v1: { campaigns: { diff --git a/src/index.ts b/src/index.ts index 5e734ed11..bb8061cf7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -7,6 +7,7 @@ export * from './common/types' export * from './messages/schedule/types' export * from './messages/types' export * from './sends/id/types' +export * from './subscription/status/types' export * from './transactional/v1/campaigns/types' export * from './users/alias/types' export * from './users/export/types' diff --git a/src/subscription/index.ts b/src/subscription/index.ts new file mode 100644 index 000000000..1b6beb17d --- /dev/null +++ b/src/subscription/index.ts @@ -0,0 +1 @@ +export * as status from './status' diff --git a/src/subscription/status/index.ts b/src/subscription/status/index.ts new file mode 100644 index 000000000..deca19334 --- /dev/null +++ b/src/subscription/status/index.ts @@ -0,0 +1,2 @@ +export * from './set' +export * from './types' diff --git a/src/subscription/status/set.test.ts b/src/subscription/status/set.test.ts new file mode 100644 index 000000000..51abea905 --- /dev/null +++ b/src/subscription/status/set.test.ts @@ -0,0 +1,52 @@ +import { post } from '../../common/request' +import { set } from '.' +import type { SubscriptionStatusSetObject } from './types' + +jest.mock('../../common/request') +const mockedPost = jest.mocked(post) + +beforeEach(() => { + jest.clearAllMocks() +}) + +describe('/subscription/status/set', () => { + const apiUrl = 'https://rest.iad-01.braze.com' + const apiKey = 'apiKey' + const data = {} + + it('calls SMS request with url and body', async () => { + mockedPost.mockResolvedValueOnce(data) + const body: SubscriptionStatusSetObject = { + subscription_group_id: 'subscription_group_identifier', + subscription_state: 'unsubscribed', + external_id: ['external_identifier'], + email: ['example1@email.com', 'example2@email.com'], + } + expect(await set(apiUrl, apiKey, body)).toBe(data) + expect(mockedPost).toBeCalledWith(`${apiUrl}/subscription/status/set`, body, { + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${apiKey}`, + }, + }) + expect(mockedPost).toBeCalledTimes(1) + }) + + it('calls email request with url and body', async () => { + mockedPost.mockResolvedValueOnce(data) + const body: SubscriptionStatusSetObject = { + subscription_group_id: 'subscription_group_identifier', + subscription_state: 'subscribed', + external_id: ['external_identifier'], + phone: ['+12223334444', '+11112223333'], + } + expect(await set(apiUrl, apiKey, body)).toBe(data) + expect(mockedPost).toBeCalledWith(`${apiUrl}/subscription/status/set`, body, { + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${apiKey}`, + }, + }) + expect(mockedPost).toBeCalledTimes(1) + }) +}) diff --git a/src/subscription/status/set.ts b/src/subscription/status/set.ts new file mode 100644 index 000000000..d2df2c43e --- /dev/null +++ b/src/subscription/status/set.ts @@ -0,0 +1,27 @@ +import { post } from '../../common/request' +import type { SubscriptionStatusSetObject } from './types' + +/** + * Update user’s subscription group status. + * + * Use these endpoints to batch update the subscription state of up to 50 users on the Braze dashboard. + * + * {@link https://www.braze.com/docs/api/endpoints/subscription_groups/post_update_user_subscription_group_status/} + * + * @param apiUrl - Braze REST endpoint. + * @param apiKey - Braze API key. + * @param body - Request parameters. + * @returns - Braze response. + */ +export function set(apiUrl: string, apiKey: string, body: SubscriptionStatusSetObject) { + const options = { + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${apiKey}`, + }, + } + + return post(`${apiUrl}/subscription/status/set`, body, options) as Promise<{ + message: 'success' | string + }> +} diff --git a/src/subscription/status/types.ts b/src/subscription/status/types.ts new file mode 100644 index 000000000..7ef6b8b24 --- /dev/null +++ b/src/subscription/status/types.ts @@ -0,0 +1,20 @@ +/** + * Request body for update user’s subscription group status. + * + * {@link https://www.braze.com/docs/api/endpoints/subscription_groups/post_update_user_subscription_group_status/#request-body} + */ +export type SubscriptionStatusSetObject = SubscriptionStatusWithPhone | SubscriptionStatusWithEmail + +interface SubscriptionStatus { + subscription_group_id: string + subscription_state: 'unsubscribed' | 'subscribed' + external_id: string[] +} + +interface SubscriptionStatusWithPhone extends SubscriptionStatus { + phone: string[] +} + +interface SubscriptionStatusWithEmail extends SubscriptionStatus { + email: string[] +}