> ## Documentation Index
> Fetch the complete documentation index at: https://docs.extole.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Map Inbound Partner Events

> Add reusable business events, input event rules, and event data to an integration that receives partner events, then verify what arrives.

This page is one part of the Management API integration guide. Start at [Create an Integration with the Management API](/technical/building-custom-integrations/integration-lifecycle/management-api-integration) for the build paths and the creation contract.

## What the Inbound Custom Workflow Creates

A complete inbound custom integration contains:

`input_event`

An inbound build carries the same three views as every other category. The configuration view comes from [Create the Integration Campaign and Component Model](/technical/building-custom-integrations/integration-lifecycle/integration-component-model); the other two, and the report runner and event stream they resolve to, come from [Add the Activity and Event Views](/technical/building-custom-integrations/integration-lifecycle/integration-activity-views). Chart and stream the canonical business events this integration produces.

The partner event name belongs in an `input_event` trigger rule. The canonical Extole event name belongs on the reusable business-event component. Do not rename the Extole business event to match the partner wire event.

This tree receives events; it does not produce them. The extension, service, or feed that sends them from the partner platform is built against [Send Platform Events to Extole](/technical/building-custom-integrations/integration-types/sending-platform-events), and an inbound integration is finished only when both halves exist.

## Settle Who Shapes the Payload First

Everything on this page assumes the event arrives with a name in `event_name` and its fields readable in `data`. That assumption holds when the sender is built for this integration — an extension, a plugin, or a service written against [Send Platform Events to Extole](/technical/building-custom-integrations/integration-types/sending-platform-events) — because whoever writes it can shape what it sends.

It does not hold when the sender is **the partner's own webhook**. A partner defines its payload for its own purposes: the event type sits in a body field rather than in `event_name`, and the interesting values sit two or three levels down. Such a webhook still reaches Extole — the named form of the Events API takes the event name from the URL and accepts any body — but what arrives is the partner's shape, not the shape this page assumes.

Reconcile that inside Extole with a prehandler, which renames the event and flattens the payload before any rule on this page sees it. [Normalize Inbound Events with a Prehandler](/technical/building-custom-integrations/integration-types/integration-prehandlers) covers the endpoint to give the partner, the decision, and the build. Two things on this page change when one is in play: the `input_event` rule lists the name the prehandler produces rather than the partner's wire name — an integration-owned name such as `example_order_completed`, never the canonical outcome name the business event itself carries — and each data component's `valueExpression` reads the flattened field rather than the partner's nesting.

The alternative — instructing the customer to build and host a service that receives the partner's webhook and re-posts it in Extole's shape — is a customer engineering project, and one this guide does not describe. Choose it deliberately or not at all.

## Add Reusable Business Events

Choose the template by business meaning:

* Use `template_transacted_business_event` when the event carries transaction value or represents the program outcome.
* Use `template_tracked_business_event` for lifecycle milestones without transaction value.

Duplicate the source component into the model component's `businessEvents` socket:

`event_name`

Use the canonical v10 name that matches the business outcome. Examples include `converted`, `shipped`, `canceled`, `returned`, `account_opened`, and `application_approved`. Do not use a transport-specific name such as `partner_order_created` as the business-event component name.

Let the partner's events decide how many you create. Enumerate the wire events in scope, decide which outcome each one represents, and create a business event for every distinct outcome — then give each the canonical name that fits it. Do not create duplicate legacy controllers alongside the reusable component.

Enumerating in the other direction is the mistake that survives: pick the canonical names first and the wire events get fitted into whichever of them is nearest. A failed authorization and a refunded charge are both tempting to call `canceled`, and an integration that calls them both that has no way to distinguish a payment that never completed from money that was taken and given back — not in a report, not in a rule, not in a clawback. `returned` is on the list above for exactly that outcome. Two wire events share one business event only when they are genuinely the same thing happening twice, and the test is whether anyone would ever need them apart.

Count the events you created against the wire events in scope before calling this stage done. Three wire events and two business events is either a deliberate merge you can name, or an outcome that quietly lost its own identity.

Set `sequence` so the events sort in lifecycle order, with the outcome event first and later milestones after it. The value orders steps within the funnel; the exact numbers matter only relative to one another.

Set the reporting names on every duplicate. `singularNounName`, `pluralNounName`, and `rateName` are what reports and the admin funnel display. The templates ship with generic values — a tracked template calls everything "Tracked Events" with a "Tracked Event Rate", and `singularNounName` defaults to an expression that echoes the display name — so two events duplicated from the same template report under identical labels until you override them. Give each canonical event its own noun and rate names, and give each an `adminUIIcon` that reads as its outcome. No two events in one integration should share an icon.

Set `aliases` to the alias set the platform already uses for that canonical event. Aliases are additional names that this business event matches, and platform consumers subscribe to them: an extension or downstream integration listening for `outcome` sees a `converted` event only because `converted` carries that alias. Read the alias set from an existing program's business event of the same name rather than inventing one. Bundled programs use these:

| Canonical event       | Aliases                                           |
| :-------------------- | :------------------------------------------------ |
| `converted`           | `conversion`, `customer`, `outcome`, `transacted` |
| `account_qualified`   | `customer`, `outcome`                             |
| `account_opened`      | `customer`                                        |
| `shipped`, `canceled` | none                                              |

Do not add partner-flavored aliases, and do not clear an alias set the template or canonical event provides. The same alias must never appear on two business events in one campaign: the match becomes ambiguous, and the event that wins is not something the configuration expresses.

Inspect the duplicated component's evaluated `journeyName` and `roleName` values. Do not hardcode one pair for every integration: these values depend on whether the event is associated with a campaign journey and on the surrounding role and journey hierarchy. Preserve the reusable template's defaults unless the integration contract requires different values, and record the published values during verification.

## Configure Input Event Rules

Duplicate `input_event` from the `rules` program into each business event's `triggerRules` socket:

`data`

Keep the duplicated rule under its source name `input_event`. Library components and bundled programs all do, so a reader recognizes the trigger by its position in the business event rather than by a component name that restates the event it listens for. The partner event name belongs in `triggerEventNames`.

When a prehandler renames the event, `triggerEventNames` lists the name the prehandler produces, not the name the partner sent. Prehandlers run before trigger rules, so a rule still listening for the wire name never matches — and it reads as correct in the component tree, which is why this is worth checking rather than assuming.

Add a legacy partner event alias only when a real sender still emits it. Document the preferred spelling and migration plan.

## Configure Event Data

Data capture is the part of the integration that carries meaning. Without it an inbound event produces a step with no transaction identifier, no person key, and no value, so nothing downstream can deduplicate, attribute, reward, or report on it. Create the data components in the same run as the business events they belong to. An integration whose `data` sockets are empty is not built, however complete its tree looks.

Take the field names from the partner's documented payload. When a partner-specific page exists in this documentation set, its payload example is the contract; otherwise use the partner's own developer documentation. Ask the requester for a sample payload only when neither source defines the field, and create the identity and deduplication fields that are defined rather than deferring the whole mapping.

Define a mapping before creating data components:

| Extole field            | Partner field          | Required                                      | Key type                   | Persist type |
| :---------------------- | :--------------------- | :-------------------------------------------- | :------------------------- | :----------- |
| `partner_conversion_id` | Transaction identifier | Yes for transaction events                    | `UNIQUE_PARTNER_EVENT_KEY` | `STEP`       |
| `partner_user_id`       | Customer identifier    | Recommended                                   | `PARTNER_PROFILE_KEY`      | `STEP`       |
| `cart_value`            | Transaction amount     | Recommended for revenue events                | `VALUE`                    | `STEP`       |
| `email`                 | Email address          | Required when no other identity is sufficient | `NONE`                     | `STEP`       |
| `first_name`            | First name             | Optional                                      | `NONE`                     | `STEP`       |
| `last_name`             | Last name              | Optional                                      | `NONE`                     | `STEP`       |
| `coupon_code`           | Applied coupon         | Optional                                      | `NONE`                     | `STEP`       |

Duplicate one `business_event_data` component into the business event's `data` socket for each field:

`event_name`

Set `valueExpression` explicitly when the partner field and Extole field have distinct names. Verify the expression against a real sanitized partner payload. Do not rely on the data component's name-derived default when the source field differs.

Quote the key with escaped double quotes, as above. A single-quoted `--data` payload cannot contain single quotes: the shell closes the string at the first one, so `getData()['order_id']` reaches the API as `getData()[order_id]`, which reads an undefined variable instead of the partner field and silently captures nothing.

Use `NO_ADDITIONAL_DATA` when the event must store only declared fields. Capture the minimum data needed for identity, deduplication, attribution, rules, and reporting.

Every business event needs its own data components — a field captured on one event is not visible on another. What each event must capture follows the table above rather than one fixed set:

* **Enough identity to resolve a person**, on every event. Capture the partner customer identifier as `PARTNER_PROFILE_KEY` whenever the partner sends a stable one, and `email` when it is the only identity available.
* **The transaction identifier as `UNIQUE_PARTNER_EVENT_KEY`, on transaction events.** An event tied to an order, a purchase, or another partner-side record needs it to deduplicate. A standalone lifecycle event such as `account_opened` has no transaction to key on, and requiring one there invents a field the partner does not send.
* **The amount as `VALUE`**, on revenue events.

Repeat the identity set on lifecycle events such as `shipped` and `canceled`: they arrive independently and must resolve to the same person and, through the transaction identifier they carry, the same original transaction.

## Verify Inbound Events

Send a synchronous test event through `POST /v6/events`. Event submission uses the same host as the management calls above but a different access token, so a caller that can create campaigns is not necessarily able to submit events. When the calling context has no event-submission token, hand the request below to whoever does, together with the values the resulting step must contain, and report the integration as built but unverified.

Put the current program label inside `data` to target this campaign during the test. The label is a testing convenience and does not belong in the partner's own payload or setup instructions.

`input_event`

Use the returned `person_id` to list the person's resulting events:

`example_order_completed`

Confirm the canonical event name and every mapped value. Use a new unique identifier for each repeat test unless duplicate handling is the behavior under test.

Test:

* Every preferred partner input event.
* Every supported legacy alias.
* Missing required identity.
* A repeated unique partner event identifier.
* Invalid amount and status values.
* Partner retry behavior.
* Campaign targeting with the current program label.
* Configuration view contents and status.
