-
Notifications
You must be signed in to change notification settings - Fork 307
feat(linkedin-audiences): upgrade API to 202603 behind feature flag #3715
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,76 @@ | ||||||
| # Breaking Changes Analysis: LinkedIn Audiences API 202505 → 202603 | ||||||
|
|
||||||
| ## Summary | ||||||
|
|
||||||
| No new DMP Segments API-specific breaking changes were introduced in the 202505–202603 window. The upgrade is primarily driven by **version sunset urgency**: 202505 sunsets on **May 15, 2026** (~1 month from today). Upgrading to 202603 (supported until March 16, 2027) ensures continuity of service. | ||||||
|
||||||
|
|
||||||
| The implementation uses a feature flag (`linkedin-audiences-canary-version`) for safe, gradual rollout with instant rollback capability. | ||||||
|
|
||||||
| --- | ||||||
|
|
||||||
| ## Critical Breaking Changes | ||||||
|
|
||||||
| **None new in 202505 → 202603 range.** | ||||||
|
|
||||||
| --- | ||||||
|
|
||||||
| ## Medium Priority Changes | ||||||
|
|
||||||
| ### 1. BATCH_CREATE Per-Element Response Schema (introduced 202502) | ||||||
|
|
||||||
| **Applies to**: `POST /rest/dmpSegments/{id}/users` with `X-RestLi-Method: BATCH_CREATE` | ||||||
|
|
||||||
| | Aspect | Pre-202502 | 202502+ (202603) | | ||||||
| | ----------------- | ------------------------------------------------------------- | ------------------------------------------------------------------------ | | ||||||
| | Validation scope | All-or-nothing: entire batch rejected on any validation error | Partial: valid elements accepted, invalid ones return per-element errors | | ||||||
| | Response body | Single error on failure | Array of per-element HTTP statuses (`201` success, `400` error) | | ||||||
| | Error attribution | No index reference | `batchIndex` field identifies failing element position | | ||||||
|
|
||||||
| **Impact on our implementation**: Our current code checks `res.status !== 200` for the top-level HTTP response and throws `RetryableError` for non-200 responses. Under 202603, a batch with some valid and some invalid elements may return HTTP `200` at the top level while individual elements have `400` status in the response body. | ||||||
|
|
||||||
| **Decision**: The existing error handling remains correct for the overall batch failure case. Per-element error handling is a potential future enhancement but is not a breaking change for the current implementation pattern (batch retries handle transient failures). | ||||||
|
||||||
| **Decision**: The existing error handling remains correct for the overall batch failure case. Per-element error handling is a potential future enhancement but is not a breaking change for the current implementation pattern (batch retries handle transient failures). | |
| **Decision**: The existing error handling remains correct only for top-level batch failures. Per-element `400` responses inside a top-level `200` response are currently treated as success by our implementation, so they are neither surfaced nor retried. This is a known behavioral gap to monitor during rollout and should be addressed in a future implementation change if element-level failure handling becomes required. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,13 @@ | ||
| import { LINKEDIN_AUDIENCES_API_VERSION } from './versioning-info' | ||
| import type { Features } from '@segment/actions-core' | ||
| import { LINKEDIN_AUDIENCES_API_VERSION, LINKEDIN_AUDIENCES_CANARY_API_VERSION } from './versioning-info' | ||
|
|
||
| export const LINKEDIN_API_VERSION = LINKEDIN_AUDIENCES_API_VERSION | ||
| export const LINKEDIN_CANARY_API_VERSION = LINKEDIN_AUDIENCES_CANARY_API_VERSION | ||
| export const BASE_URL = 'https://api.linkedin.com/rest' | ||
| export const LINKEDIN_SOURCE_PLATFORM = 'SEGMENT' | ||
|
|
||
| export const FLAGON_NAME = 'linkedin-audiences-canary-version' | ||
|
|
||
| export function getApiVersion(features?: Features): string { | ||
| return features && features[FLAGON_NAME] ? LINKEDIN_CANARY_API_VERSION : LINKEDIN_API_VERSION | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,13 @@ | ||
| import nock from 'nock' | ||
| import { createTestEvent, createTestIntegration } from '@segment/actions-core' | ||
| import Destination from '../../index' | ||
| import { BASE_URL, LINKEDIN_SOURCE_PLATFORM } from '../../constants' | ||
| import { | ||
| BASE_URL, | ||
| LINKEDIN_SOURCE_PLATFORM, | ||
| LINKEDIN_API_VERSION, | ||
| LINKEDIN_CANARY_API_VERSION, | ||
| FLAGON_NAME | ||
| } from '../../constants' | ||
|
|
||
| const testDestination = createTestIntegration(Destination) | ||
|
|
||
|
|
@@ -865,4 +871,68 @@ describe('LinkedinAudiences.updateAudience', () => { | |
| ).rejects.toThrow('The value of `source_segment_id` and `personas_audience_key` must match.') | ||
| }) | ||
| }) | ||
|
|
||
| describe('API Version Feature Flag', () => { | ||
| it('should use stable API version by default (no feature flag)', async () => { | ||
| nock(`${BASE_URL}/dmpSegments`) | ||
| .get(/.*/) | ||
| .query(() => true) | ||
| .reply(200, { elements: [{ id: 'dmp_segment_id' }] }) | ||
|
|
||
| const batchUpdateMock = nock(`${BASE_URL}/dmpSegments/dmp_segment_id/users`) | ||
| .post(/.*/, updateUsersRequestBody) | ||
| .matchHeader('linkedin-version', LINKEDIN_API_VERSION) | ||
| .reply(200) | ||
|
Comment on lines
+875
to
+885
|
||
|
|
||
| await expect( | ||
| testDestination.testAction('updateAudience', { | ||
| event, | ||
| settings: { | ||
| ad_account_id: '123', | ||
| send_email: true, | ||
| send_google_advertising_id: true | ||
| }, | ||
| useDefaultMappings: true, | ||
| auth, | ||
| mapping: { | ||
| personas_audience_key: 'personas_test_audience' | ||
| } | ||
| // No features parameter — stable version should be used | ||
| }) | ||
| ).resolves.not.toThrowError() | ||
|
|
||
| expect(batchUpdateMock.isDone()).toBe(true) | ||
| }) | ||
|
|
||
| it('should use canary API version when feature flag is enabled', async () => { | ||
| nock(`${BASE_URL}/dmpSegments`) | ||
| .get(/.*/) | ||
| .query(() => true) | ||
| .reply(200, { elements: [{ id: 'dmp_segment_id' }] }) | ||
|
|
||
| const batchUpdateMock = nock(`${BASE_URL}/dmpSegments/dmp_segment_id/users`) | ||
| .post(/.*/, updateUsersRequestBody) | ||
| .matchHeader('linkedin-version', LINKEDIN_CANARY_API_VERSION) | ||
| .reply(200) | ||
|
|
||
| await expect( | ||
| testDestination.testAction('updateAudience', { | ||
| event, | ||
| settings: { | ||
| ad_account_id: '123', | ||
| send_email: true, | ||
| send_google_advertising_id: true | ||
| }, | ||
| useDefaultMappings: true, | ||
| auth, | ||
| mapping: { | ||
| personas_audience_key: 'personas_test_audience' | ||
| }, | ||
| features: { [FLAGON_NAME]: true } | ||
| }) | ||
| ).resolves.not.toThrowError() | ||
|
|
||
| expect(batchUpdateMock.isDone()).toBe(true) | ||
| }) | ||
| }) | ||
| }) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,12 @@ | ||
| /** LINKEDIN_AUDIENCES_API_VERSION | ||
| * LinkedIn Audiences API version. | ||
| * LinkedIn Audiences API version (stable/production). | ||
| * API reference: https://learn.microsoft.com/en-us/linkedin/marketing/integrations/ads-audience-management/audience-api?view=li-lms-2024-05 | ||
| * Changelog: https://learn.microsoft.com/en-us/linkedin/marketing/changelog | ||
| */ | ||
| export const LINKEDIN_AUDIENCES_API_VERSION = '202505' | ||
|
|
||
| /** LINKEDIN_AUDIENCES_CANARY_API_VERSION | ||
| * LinkedIn Audiences API version (canary/feature-flagged). | ||
| * Testing new version 202603 behind feature flag. | ||
| */ | ||
| export const LINKEDIN_AUDIENCES_CANARY_API_VERSION = '202603' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
extendRequestalready injects theLinkedIn-Versionheader for all requests. Setting a per-request version header here (with a different key casing) overrides the default and makes it easier for the versioning behavior to drift between endpoints. Consider relying onextendRequestfor the version header (keep onlyX-RestLi-Methodhere), or at least standardize the header key casing to a single form across the destination.