Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Region } from './types'
import { defaultValues, InvalidAuthenticationError } from '@segment/actions-core'
import { getAuthToken } from './utils'
import trackConversion from './trackConversion'
import { AMAZON_CONVERSIONS_API_PROFILES_VERSION } from './versioning-info'

const destination: DestinationDefinition<Settings> = {
name: 'Amazon Conversions Api',
Expand All @@ -30,13 +31,15 @@ const destination: DestinationDefinition<Settings> = {
},
advertiserId: {
label: 'Amazon Advertiser ID',
description: 'Your Amazon Advertiser Account ID. This must be a numeric value. Use Amazon DSP CFID and not Entity ID.',
description:
'Your Amazon Advertiser Account ID. This must be a numeric value. Use Amazon DSP CFID and not Entity ID.',
type: 'string',
required: true
},
dataSetName: {
label: 'Dataset Name',
description: 'Amazon Ads organizes uploaded data into datasets, which are logical groupings used to separate and categorize events from your sources. The default dataset name (if not provided) is Default_Events. All events within a dataset will appear in Amazon Ads Data Manager under the name you provide here. New destination? We recommend providing a dataset name during initial setup. Existing destination? We strongly recommend reading the [FAQ](https://www.twilio.com/docs/segment/connections/destinations/catalog/actions-amazon-conversions-api#what-is-a-dataset-and-how-does-amazon-use-the-dataset-name) before updating your dataset name, as changes may impact your existing events.',
description:
'Amazon Ads organizes uploaded data into datasets, which are logical groupings used to separate and categorize events from your sources. The default dataset name (if not provided) is Default_Events. All events within a dataset will appear in Amazon Ads Data Manager under the name you provide here. New destination? We recommend providing a dataset name during initial setup. Existing destination? We strongly recommend reading the [FAQ](https://www.twilio.com/docs/segment/connections/destinations/catalog/actions-amazon-conversions-api#what-is-a-dataset-and-how-does-amazon-use-the-dataset-name) before updating your dataset name, as changes may impact your existing events.',
type: 'string',
required: false
}
Expand All @@ -47,23 +50,28 @@ const destination: DestinationDefinition<Settings> = {
}

const { dataSetName, advertiserId } = settings

if(dataSetName && !/^[A-Za-z][A-Za-z0-9_-]{4,99}$/.test(dataSetName ?? '')){
throw new InvalidAuthenticationError('Dataset Name must start with a letter and can only contain letters, numbers, underscores, or hyphens. It must be between 5 and 100 characters long.')

if (dataSetName && !/^[A-Za-z][A-Za-z0-9_-]{4,99}$/.test(dataSetName ?? '')) {
throw new InvalidAuthenticationError(
'Dataset Name must start with a letter and can only contain letters, numbers, underscores, or hyphens. It must be between 5 and 100 characters long.'
)
}
if(!/^\d+$/.test(advertiserId)) {

if (!/^\d+$/.test(advertiserId)) {
throw new InvalidAuthenticationError('Advertising ID must be numeric')
}

return await request<RefreshTokenResponse>(`${settings.region}/v2/profiles`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Amazon-Advertising-API-ClientID': process.env.ACTIONS_AMAZON_CONVERSIONS_API_CLIENT_ID || ''
},
timeout: 2500
})
return await request<RefreshTokenResponse>(
`${settings.region}/${AMAZON_CONVERSIONS_API_PROFILES_VERSION}/profiles`,
{
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Amazon-Advertising-API-ClientID': process.env.ACTIONS_AMAZON_CONVERSIONS_API_CLIENT_ID || ''
},
timeout: 2500
}
)
},
refreshAccessToken: async (request, { auth }) => {
const authToken = await getAuthToken(request, auth)
Expand Down Expand Up @@ -197,7 +205,7 @@ const destination: DestinationDefinition<Settings> = {
eventType: 'OTHER'
},
type: 'automatic'
},
}
],
actions: {
trackConversion
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import type {
} from '../types'
import { MatchKeyTypeV1, Region, ConversionTypeV2 } from '../types'
import type { Payload } from './generated-types'
import { AMAZON_CONVERSIONS_API_EVENTS_VERSION } from '../versioning-info'

/**
* Helper function to validate if a string value exists and is not empty
Expand Down Expand Up @@ -143,17 +144,20 @@ export async function sendEventsRequest<ImportConversionEventsResponse>(
// Ensure eventData is always an array
const events = Array.isArray(eventData) ? eventData : [eventData]

return await request<ImportConversionEventsResponse>(`${settings.region}/adsApi/v1/create/events`, {
method: 'POST',
json: {
events: events
},
headers: {
'Amazon-Ads-AccountId': settings.advertiserId,
'Amazon-Ads-ClientId': process.env.ACTIONS_AMAZON_CONVERSIONS_API_CLIENT_ID || ''
},
throwHttpErrors: false
})
return await request<ImportConversionEventsResponse>(
`${settings.region}/adsApi/${AMAZON_CONVERSIONS_API_EVENTS_VERSION}/create/events`,
{
method: 'POST',
json: {
events: events
},
headers: {
'Amazon-Ads-AccountId': settings.advertiserId,
'Amazon-Ads-ClientId': process.env.ACTIONS_AMAZON_CONVERSIONS_API_CLIENT_ID || ''
},
throwHttpErrors: false
}
)
}

/**
Expand Down Expand Up @@ -379,7 +383,7 @@ export function prepareEventData(payload: Payload, settings: Settings): EventDat
name: payload.name,
conversionType: payload.eventType as ConversionTypeV2,
eventSource: payload.eventActionSource.toUpperCase(),
eventIngestionMethod: 'SERVER_TO_SERVER',
eventIngestionMethod: 'SERVER_TO_SERVER',
...(settings.dataSetName ? { dataSetName: settings.dataSetName } : {})
}

Expand All @@ -389,7 +393,6 @@ export function prepareEventData(payload: Payload, settings: Settings): EventDat
eventTime: payload.timestamp
}


if (matchKeys) {
eventData.matchKeys = matchKeys
}
Expand All @@ -398,20 +401,21 @@ export function prepareEventData(payload: Payload, settings: Settings): EventDat

Object.assign(eventData, {
...(payload.value !== undefined && { value: payload.value }),
...(payload.eventType === ConversionTypeV2.OFF_AMAZON_PURCHASES && payload.currencyCode && {
currencyCode: payload.currencyCode as CurrencyCodeV1
}),
...(payload.eventType === ConversionTypeV2.OFF_AMAZON_PURCHASES && payload.unitsSold !== undefined && {
unitsSold: payload.unitsSold
}),
...(payload.eventType === ConversionTypeV2.OFF_AMAZON_PURCHASES &&
payload.currencyCode && {
currencyCode: payload.currencyCode as CurrencyCodeV1
}),
...(payload.eventType === ConversionTypeV2.OFF_AMAZON_PURCHASES &&
payload.unitsSold !== undefined && {
unitsSold: payload.unitsSold
}),
...(payload.clientDedupeId && { eventId: payload.clientDedupeId }),
...(payload.dataProcessingOptions?.[0] && {
dataProcessingOptions: {
options: payload.dataProcessingOptions[0]
} as DataProcessingOptions
}),


...(consent && { consent }),
...(payload.customAttributes && {
customData: customAttributeArray.length > 0 ? customAttributeArray : undefined
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/** AMAZON_CONVERSIONS_API_PROFILES_VERSION
* Profiles endpoint version: /v2/profiles
* API reference: https://advertising.amazon.com/API/docs/en-us/reference/2/profiles#tag/Profiles/operation/listProfiles
*/
export const AMAZON_CONVERSIONS_API_PROFILES_VERSION = 'v2'

/** AMAZON_CONVERSIONS_API_EVENTS_VERSION
* Events endpoint version: /v1/events
* API reference: https://advertising.amazon.com/API/docs/en-us/amazon-ads/1-0/betas#tag/Events/operation/CreateEvent
*/
export const AMAZON_CONVERSIONS_API_EVENTS_VERSION = 'v1'
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ import type { Settings } from '../generated-types'
import type { Payload } from './generated-types'

import { extractSchemaFromEvent } from './avo'
import { AVO_API_VERSION } from '../versioning-info'

const processEvents = async (request: RequestClient, settings: Settings, payload: Payload[]) => {
const events = payload.map((value) => extractSchemaFromEvent(value, settings.appVersionPropertyName))

const endpoint = 'https://api.avo.app/inspector/segment/v1/track'
const endpoint = `https://api.avo.app/inspector/segment/${AVO_API_VERSION}/track`

return request(endpoint, {
method: 'post',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/** AVO_API_VERSION
* Inspector track endpoint version.
* API reference: https://www.avo.app/docs/implementation/devs-101#inspector-api
*/
export const AVO_API_VERSION = 'v1'
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { DestinationDefinition } from '@segment/actions-core'
import type { Settings } from './generated-types'
import { actionDefinition as sendEmail } from './sendEmail'
import { actionDefinition as previewApiLookup } from './previewApiLookup'
import { ENGAGE_MESSAGING_SENDGRID_API_VERSION } from './versioning-info'

export const destinationDefinition: DestinationDefinition<Settings> = {
name: 'Engage Messaging SendGrid',
Expand Down Expand Up @@ -59,7 +60,7 @@ export const destinationDefinition: DestinationDefinition<Settings> = {
}
},
testAuthentication: (request) => {
return request('https://api.sendgrid.com/v3/mail_settings')
return request(`https://api.sendgrid.com/${ENGAGE_MESSAGING_SENDGRID_API_VERSION}/mail_settings`)
}
},
actions: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { insertEmailPreviewText } from './insertEmailPreviewText'
import cheerio from 'cheerio'
import { isRestrictedDomain } from './isRestrictedDomain'
import { UnlayerResponse } from './UnlayerResponse'
import { ENGAGE_MESSAGING_SENDGRID_API_VERSION } from '../versioning-info'

export const EXTERNAL_ID_KEY = 'email'

Expand Down Expand Up @@ -260,7 +261,10 @@ export class SendEmailPerformer extends MessageSendPerformer<Settings, Payload>
json: mailContent
}
//this.statsClient?.set('message_body_size', JSON.stringify(req).length) // Commented due to performance issues
const response = await this.request('https://api.sendgrid.com/v3/mail/send', req)
const response = await this.request(
`https://api.sendgrid.com/${ENGAGE_MESSAGING_SENDGRID_API_VERSION}/mail/send`,
req
)
if (this.payload?.eventOccurredTS != undefined) {
this.statsClient?.histogram(
'eventDeliveryTS',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/** ENGAGE_MESSAGING_SENDGRID_API_VERSION
* SendGrid mail send API version.
* API reference: https://docs.sendgrid.com/api-reference/mail-send/mail-send
*/
export const ENGAGE_MESSAGING_SENDGRID_API_VERSION = 'v3'
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
export const API_VERSION = 'v24.0'
import { FACEBOOK_CUSTOM_AUDIENCES_API_VERSION, FACEBOOK_CUSTOM_AUDIENCES_CANARY_API_VERSION } from './versioning-info'

export const CANARY_API_VERSION = 'v24.0'
export const API_VERSION = FACEBOOK_CUSTOM_AUDIENCES_API_VERSION

export const CANARY_API_VERSION = FACEBOOK_CUSTOM_AUDIENCES_CANARY_API_VERSION

export const FACEBOOK_CUSTOM_AUDIENCE_FLAGON = 'facebook-custom-audience-actions-canary-version'

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/** FACEBOOK_CUSTOM_AUDIENCES_API_VERSION
* Facebook Custom Audiences API version.
* API reference: https://developers.facebook.com/docs/marketing-api/audiences/guides/custom-audiences
*/
export const FACEBOOK_CUSTOM_AUDIENCES_API_VERSION = 'v24.0'

/** FACEBOOK_CUSTOM_AUDIENCES_CANARY_API_VERSION
* Facebook Custom Audiences API canary version.
* API reference: https://developers.facebook.com/docs/marketing-api/audiences/guides/custom-audiences
*/
export const FACEBOOK_CUSTOM_AUDIENCES_CANARY_API_VERSION = 'v24.0'
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { ModifiedResponse, RequestClient } from '@segment/actions-core'
import type { MappingSettings } from '../postSheet/operations'

const API_VERSION = 'v4'
import { GOOGLE_SHEETS_API_VERSION } from '../versioning-info'

export type GetResponse = {
range: string
Expand All @@ -17,7 +16,7 @@ export class GoogleSheets {

get = async (mappingSettings: MappingSettings, range: string): Promise<ModifiedResponse<GetResponse>> => {
return this.request(
`https://sheets.googleapis.com/${API_VERSION}/spreadsheets/${mappingSettings.spreadsheetId}/values/${mappingSettings.spreadsheetName}!${range}`,
`https://sheets.googleapis.com/${GOOGLE_SHEETS_API_VERSION}/spreadsheets/${mappingSettings.spreadsheetId}/values/${mappingSettings.spreadsheetName}!${range}`,
{
method: 'get',
skipResponseCloning: true
Expand All @@ -27,7 +26,7 @@ export class GoogleSheets {

batchUpdate = async (mappingSettings: MappingSettings, batchPayload: { range: string; values: string[][] }[]) => {
return this.request(
`https://sheets.googleapis.com/${API_VERSION}/spreadsheets/${mappingSettings.spreadsheetId}/values:batchUpdate`,
`https://sheets.googleapis.com/${GOOGLE_SHEETS_API_VERSION}/spreadsheets/${mappingSettings.spreadsheetId}/values:batchUpdate`,
{
method: 'post',
skipResponseCloning: true,
Expand All @@ -54,7 +53,7 @@ export class GoogleSheets {

append = async (mappingSettings: MappingSettings, range: string, values: string[][]) => {
return this.request(
`https://sheets.googleapis.com/${API_VERSION}/spreadsheets/${mappingSettings.spreadsheetId}/values/${mappingSettings.spreadsheetName}!${range}:append?valueInputOption=${mappingSettings.dataFormat}&insertDataOption=INSERT_ROWS`,
`https://sheets.googleapis.com/${GOOGLE_SHEETS_API_VERSION}/spreadsheets/${mappingSettings.spreadsheetId}/values/${mappingSettings.spreadsheetName}!${range}:append?valueInputOption=${mappingSettings.dataFormat}&insertDataOption=INSERT_ROWS`,
{
method: 'post',
skipResponseCloning: true,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/** GOOGLE_SHEETS_API_VERSION
* Google Sheets API version.
* API reference: https://developers.google.com/workspace/sheets/api/reference/rest
*/
export const GOOGLE_SHEETS_API_VERSION = 'v4'
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { defaultValues, IntegrationError } from '@segment/actions-core'
import { TaboolaClient } from './syncAudience/client'

import syncAudience from './syncAudience'
import { TABOOLA_API_VERSION } from './versioning-info'

const destination: AudienceDestinationDefinition<Settings, AudienceSettings> = {
name: 'Taboola (Actions)',
Expand Down Expand Up @@ -97,7 +98,7 @@ const destination: AudienceDestinationDefinition<Settings, AudienceSettings> = {
const accessToken = (await TaboolaClient.refreshAccessToken(request, createAudienceInput.settings)).accessToken

const response = await request(
`https://backstage.taboola.com/backstage/api/1.0/${accountId}/audience_onboarding/create`,
`https://backstage.taboola.com/backstage/api/${TABOOLA_API_VERSION}/${accountId}/audience_onboarding/create`,
{
method: 'post',
json: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { ModifiedResponse } from '@segment/actions-core'
import { RequestClient, IntegrationError } from '@segment/actions-core'
import { Payload } from './generated-types'
import { AudienceSettings, Settings } from '../generated-types'
import { TABOOLA_API_VERSION } from '../versioning-info'

interface ClusterItem {
user_id: string
Expand Down Expand Up @@ -89,7 +90,7 @@ export class TaboolaClient {
if (identities.length > 0) {
taboolaRequests.push(
this.request(
`https://backstage.taboola.com/backstage/api/1.0/${
`https://backstage.taboola.com/backstage/api/${TABOOLA_API_VERSION}/${
this.audienceSettings?.account_id as string
}/audience_onboarding`,
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/** TABOOLA_API_VERSION
* Taboola Backstage API version.
* API reference: https://developers.taboola.com/backstage-api/reference/create-a-first-party-audience
*/
export const TABOOLA_API_VERSION = '1.0'
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { defaultValues, DestinationDefinition } from '@segment/actions-core'
import type { Settings } from './generated-types'
import { TIKTOK_OFFLINE_CONVERSIONS_API_VERSION } from './versioning-info'
import trackPaymentOfflineConversion from './trackPaymentOfflineConversion'
import trackNonPaymentOfflineConversion from './trackNonPaymentOfflineConversion'
import reportOfflineEvent from './reportOfflineEvent'
Expand Down Expand Up @@ -73,15 +74,18 @@ const destination: DestinationDefinition<Settings> = {
}
},
testAuthentication: (request, { settings }) => {
return request('https://business-api.tiktok.com/open_api/v1.3/offline/track/', {
method: 'post',
json: {
event_set_id: settings.eventSetID,
event: 'Test Event',
timestamp: '',
context: {}
return request(
`https://business-api.tiktok.com/open_api/${TIKTOK_OFFLINE_CONVERSIONS_API_VERSION}/offline/track/`,
{
method: 'post',
json: {
event_set_id: settings.eventSetID,
event: 'Test Event',
timestamp: '',
context: {}
}
}
})
)
}
},
extendRequest({ settings }) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { RequestClient, PayloadValidationError } from '@segment/actions-core'
import { Settings } from './generated-types'
import { TIKTOK_OFFLINE_CONVERSIONS_API_VERSION } from './versioning-info'
import { Payload as ReportOfflineEventPayload } from './reportOfflineEvent/generated-types'
import { Payload as TrackNonPaymentOfflineConversionPayload } from './trackNonPaymentOfflineConversion/generated-types'
import { Payload as TrackPaymentOfflineConversionPayload } from './trackPaymentOfflineConversion/generated-types'
Expand Down Expand Up @@ -31,7 +32,7 @@ export function performOfflineEvent(request: RequestClient, settings: Settings,

if (payloadUrl) urlTtclid = payloadUrl.searchParams.get('ttclid')

return request('https://business-api.tiktok.com/open_api/v1.3/event/track/', {
return request(`https://business-api.tiktok.com/open_api/${TIKTOK_OFFLINE_CONVERSIONS_API_VERSION}/event/track/`, {
method: 'post',
json: {
event_source: 'offline',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/** TIKTOK_OFFLINE_CONVERSIONS_API_VERSION
* TikTok offline conversions API version.
* API reference: https://business-api.tiktok.com/portal/docs?id=1758428013689857
*/
export const TIKTOK_OFFLINE_CONVERSIONS_API_VERSION = 'v1.3'
Loading