Skip to content

STRATCONN-6441 - [Facebook CAPI] - AppendValue support for custom and purchase events#3793

Draft
joe-ayoub-segment wants to merge 13 commits into
mainfrom
fb-appendvalue
Draft

STRATCONN-6441 - [Facebook CAPI] - AppendValue support for custom and purchase events#3793
joe-ayoub-segment wants to merge 13 commits into
mainfrom
fb-appendvalue

Conversation

@joe-ayoub-segment
Copy link
Copy Markdown
Contributor

Adding support for AppendValue to Facebook CAPI custom and purchase events.

Testing

Unit tests and staging tests to be done.

Security Review

Please ensure sensitive data is properly protected in your integration.

  • Reviewed all field definitions for sensitive data (API keys, tokens, passwords, client secrets) and confirmed they use type: 'password'

New Destination Checklist

  • Extracted all action API versions to verioning-info.ts file. example

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds support for Facebook CAPI’s AppendValue event shape for Custom and Purchase actions by introducing new append-related fields, a feature flag, and conversion logic in the shared event-data builders.

Changes:

  • Introduces AppendValueEventData / AppendEventDetails types and a FEATURE_FLAG_APPEND_VALUE flag.
  • Extends shared getCustomEventData / getPurchaseEventData to optionally convert outgoing payloads into AppendValue requests.
  • Adds new action fields (is_append_event, append_event_details) and purchase fields (order_id, predicted_ltv) and regenerates action payload types accordingly.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
packages/destination-actions/src/destinations/facebook-conversions-api/shared/types.ts Adds new AppendValue-related TS interfaces for event payload shaping.
packages/destination-actions/src/destinations/facebook-conversions-api/shared/functions.ts Passes features/statsContext into data builders and adds AppendValue conversion + validation.
packages/destination-actions/src/destinations/facebook-conversions-api/shared/fields.ts Adds append configuration fields and extends purchase/custom field sets.
packages/destination-actions/src/destinations/facebook-conversions-api/shared/constants.ts Introduces FEATURE_FLAG_APPEND_VALUE.
packages/destination-actions/src/destinations/facebook-conversions-api/purchase2/generated-types.ts Regenerates payload types to include append + new purchase fields.
packages/destination-actions/src/destinations/facebook-conversions-api/purchase/generated-types.ts Regenerates payload types to include append + new purchase fields.
packages/destination-actions/src/destinations/facebook-conversions-api/custom2/generated-types.ts Regenerates payload types to include append configuration fields.
packages/destination-actions/src/destinations/facebook-conversions-api/custom/generated-types.ts Regenerates payload types to include append configuration fields.
Comments suppressed due to low confidence (3)

packages/destination-actions/src/destinations/facebook-conversions-api/shared/functions.ts:268

  • Same issue as custom: if is_append_event is true but FEATURE_FLAG_APPEND_VALUE is not enabled, the code returns a normal Purchase event rather than failing fast. Consider explicitly erroring (or otherwise surfacing) this unsupported configuration to avoid silently sending the wrong event type.
export function getPurchaseEventData(payload: PurchasePayload | Purchase2Payload, features?: Features, statsContext?: StatsContext): PurchaseEventData | AppendValueEventData {
  const baseEventData = getBaseEventData(payload)

  const { is_append_event, append_event_details, order_id, predicted_ltv, custom_data, currency, value, content_ids, net_revenue, content_name, content_type, num_items, contents } =
    payload

  const data: PurchaseEventData = {
    event_name: 'Purchase',
    ...baseEventData,
    custom_data: {
      ...custom_data,
      currency,
      value,
      ...(order_id && { order_id }),
      ...(typeof predicted_ltv === 'number' && { predicted_ltv }),
      ...(typeof net_revenue === 'number' && { net_revenue }),
      ...(Array.isArray(content_ids) && content_ids.length > 0 && { content_ids }),
      ...(content_name && { content_name }),
      ...(content_type && { content_type }),
      ...(contents && { contents }),
      ...(typeof num_items === 'number' && { num_items })
    }
  }

  if(features?.[FEATURE_FLAG_APPEND_VALUE] && is_append_event && append_event_details) {
    return convertToAppendValueEventData(data, append_event_details as AppendEventDetails, statsContext)
  }

  return data  

packages/destination-actions/src/destinations/facebook-conversions-api/shared/fields.ts:657

  • purchaseFields now exposes is_append_event/append_event_details and also order_id/predicted_ltv, but the Purchase action only uses getPurchaseEventData (which handles these fields) when FEATURE_FLAG_PURCHASE is enabled. When that flag is off, the legacy perform path does not send order_id/predicted_ltv and cannot emit AppendValue, so these mapped fields will be silently ignored. Either wire these fields into the legacy path or fail fast / gate the fields so they can't be configured when unsupported.
export const purchaseFields: Record<string, InputField> = {
  is_append_event,
  append_event_details,
  action_source: { ...action_source, required: true },
  currency: { ...currency, required: true },
  event_time: { ...event_time, required: true },
  user_data: user_data_field,
  app_data_field,
  value: {
    ...value,
    required: true,
    default: { '@path': '$.properties.revenue' }
  },
  order_id,
  predicted_ltv,
  net_revenue,

packages/destination-actions/src/destinations/facebook-conversions-api/shared/fields.ts:835

  • customFields now exposes is_append_event/append_event_details, but the Custom action only routes through getCustomEventData (which can convert to AppendValue) when FEATURE_FLAG_CUSTOM is enabled. When that flag is off, the legacy perform path ignores these fields and will never send an AppendValue event. Either add AppendValue support to the legacy path or prevent this configuration when the refactor flag is disabled (so the fields aren't silently ignored).
export const customFields: Record<string, InputField> = {
  is_append_event,
  append_event_details,
  action_source: { ...action_source, required: true },

Copilot AI review requested due to automatic review settings May 14, 2026 15:52
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (1)

packages/destination-actions/src/destinations/facebook-conversions-api/shared/fields.ts:835

  • customFields exposes is_append_event and append_event_details, but the legacy (FEATURE_FLAG_CUSTOM off) implementation in custom/index.ts never calls getCustomEventData, so the append-value toggle has no effect unless the refactor flag is enabled. To avoid a confusing no-op configuration, either implement append-value behavior for the legacy code path too or gate/hide these fields when the refactor flag isn’t enabled.
export const customFields: Record<string, InputField> = {
  is_append_event,
  append_event_details,
  action_source: { ...action_source, required: true },

Copilot AI review requested due to automatic review settings May 15, 2026 09:52
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (1)

packages/destination-actions/src/destinations/facebook-conversions-api/shared/functions.ts:276

  • When is_append_event is true but append_event_details is missing/undefined, this currently returns a normal Purchase event instead of failing fast. Since the UI makes append_event_details required when is_append_event is true, it’s better to enforce the same invariant at runtime and throw a PayloadValidationError if details are not provided.
  if(is_append_event) {
    if(!features?.[FEATURE_FLAG_APPEND_VALUE]) {
      throw new PayloadValidationError('AppendValue is not enabled for this destination. Please contact Segment support so the feature can be enabled for your Segment workspace.')
    }
    if(append_event_details) {
      return convertToAppendValueEventData(data, append_event_details as AppendEventDetails, statsContext)
    }
  }

Co-authored-by: Copilot Autofix powered by AI <[email protected]>
Copilot AI review requested due to automatic review settings May 15, 2026 12:56
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated 7 comments.

Comments suppressed due to low confidence (1)

packages/destination-actions/src/destinations/facebook-conversions-api/shared/functions.ts:274

  • When is_append_event is true but append_event_details is missing/undefined, this function currently returns a normal Purchase payload. That will silently emit a non-AppendValue event even though the caller opted into append mode. Consider throwing a PayloadValidationError if is_append_event is true and append_event_details is not provided (after checking the feature flag).
    if(!features?.[FEATURE_FLAG_APPEND_VALUE]) {
      throw new PayloadValidationError('AppendValue is not enabled for this destination. Please contact Segment support so the feature can be enabled for your Segment workspace.')
    }
    if(append_event_details) {
      return convertToAppendValueEventData(data, append_event_details as AppendEventDetails, statsContext)

Co-authored-by: Copilot Autofix powered by AI <[email protected]>
Copilot AI review requested due to automatic review settings May 15, 2026 13:05
joe-ayoub-segment and others added 4 commits May 15, 2026 14:05
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (4)

packages/destination-actions/src/destinations/facebook-conversions-api/shared/fields.ts:224

  • ctwa_clid is added to the shared user data schema, but the legacy hash_user_data implementation (used in the non-refactored perform paths) doesn’t map it through to Facebook, so this field will be silently ignored when the refactor feature flags are OFF. Consider adding ctwa_clid passthrough to the legacy user-data mapping (or ensuring all code paths use getUserData).
    ctwa_clid: {
      label: 'Click to WhatsApp Click ID (ctwa_clid)',
      description: 'Click ID generated by Meta for ads that click to WhatsApp.',
      type: 'string'
    }

packages/destination-actions/src/destinations/facebook-conversions-api/shared/functions.ts:273

  • Formatting here is inconsistent with the rest of the file (missing spaces in if (...) / if (!...)), which will likely fail Prettier/ESLint checks. Please run Prettier (or reformat this block).
  if(is_append_event) {
    if(!features?.[FEATURE_FLAG_APPEND_VALUE]) {
      throw new PayloadValidationError('AppendValue is not enabled for this destination. Please contact Segment support so the feature can be enabled for your Segment workspace.')
    }
    if(append_event_details) {

packages/destination-actions/src/destinations/facebook-conversions-api/shared/functions.ts:347

  • convertToAppendValueEventData has formatting that diverges from the repo’s Prettier conventions (e.g., if(!original_event_time) missing spacing). Please run Prettier on this function to avoid formatting/lint failures and keep it readable.
  if(!original_event_time) {
    statsClient?.incr('append_value_event.error', 1, tags)
    throw new PayloadValidationError('If sending an AppendValue, Append Event Details field "Original Event Time" is required')
  }

packages/destination-actions/src/destinations/facebook-conversions-api/shared/fields.ts:662

  • order_id / predicted_ltv are now included in purchaseFields, but the legacy Purchase perform implementation (used when FEATURE_FLAG_PURCHASE is OFF) does not include these in the outbound custom_data, so they’ll be silently dropped for some workspaces. Either add them to the legacy request mapping or ensure the shared send/getPurchaseEventData path is used when these fields are set.
  order_id,
  predicted_ltv,
  net_revenue,

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants