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

# Use your event sources and audiences on each seller account

> Map your event sources and audiences to the pixels, datasets and lists on each seller account, so conversion goals and audience targeting work on every platform you buy on

## How it works

You define an **event source** (a stream of conversions you send with
[`log_event`](/v2/guides/log-events)) or an **audience** (a list of people you
sync with `save_audience`) once, for the advertiser. A seller account such as a
Meta ad account or a Snap ad account only understands its own objects: a Meta
dataset, a Snap Pixel, a TikTok pixel, a LinkedIn conversion rule, a Meta Custom
Audience. A **mapping** tells Apostra which of those objects is the same thing
as yours on that account.

There are two kinds of object on a seller account:

* **Yours, once mapped.** A pixel or list you map to one of your event sources
  or audiences works in every campaign that runs on that account.
* **Seller-managed or unmapped.** Objects that belong to one storefront, such as
  a Meta Instant Forms leads source, or any object you leave unmapped, stay
  specific to that storefront. They pass through unchanged and are usable in
  that storefront's own campaigns. Do not map your event sources to
  seller-managed objects.

The flow is always map, confirm, buy:

1. **Map.** Save the mapping with `sellerAccounts` on `save_event_source` or
   `save_audience`, or pick it on the Connections page.
2. **Confirm.** Apostra asks the seller account to confirm the object is there.
   The mapping reads `pending`, then `synced`, typically within a minute. An
   audience also reports the seller's own size and match rate.
3. **Buy.** When a media buy's optimization goal names your event source,
   Apostra sends the seller the mapped platform object instead of your id.

Apostra never creates a pixel or a dataset for you. Create it in the platform's
own console first, then map it. Saving a mapping reads what is on the account and
records one id; it never changes anything on the platform.

<Note>
  **Action needed if you name your own event sources in conversion goals.** Map
  each event source on every seller account you buy on. A media buy whose goal
  names an event source with no mapping on that account fails before anything
  reaches the seller. Goals that carry a raw platform pixel id, buys with no
  event goal, and a Meta product's explicit `pixelId` behave as before.
</Note>

## Find what is on each account

Open the Connections page for one connected account. It lists the pixels,
datasets and audiences already there, and whether each is yours (**Mapped to**)
or only on that storefront. See
[Open Media Partners](/v2/buyer/storefronts/tasks/open-connections-page#event-sources-and-audiences-on-a-connected-account).

Over MCP, call `open_connections_page` with a `connectionId` and `accountId`:

```json theme={null}
{
  "name": "open_connections_page",
  "arguments": { "connectionId": "992", "accountId": "301" }
}
```

To read the same list as data, call `get` with the connection, its inventory and
one account:

```json theme={null}
{
  "kind": "connection",
  "id": "992",
  "include": ["inventory"],
  "connectionAccountId": "301"
}
```

Each inventory item carries the platform's own id as `upstreamObjectId`. That is
the value you pass as `sellerId` when you map. The account `id` (here `301`) is
the `accounts[].id` from `get({ "kind": "connection", "id": "992" })`.

## Map an event source

Save the event source with `sellerAccounts`. Each entry names the seller account
and the id of the object on it:

```json theme={null}
{
  "advertiserId": "42",
  "idempotencyKey": "map-purchase-completed-2026-10-11-001",
  "eventSources": [
    {
      "eventSourceId": "purchase-completed",
      "name": "Purchase Completed",
      "eventTypes": ["purchase"],
      "actionSource": "website",
      "valueCurrencies": ["USD"],
      "sellerAccounts": [
        { "accountId": "301", "sellerId": "1234567890123456" }
      ]
    }
  ]
}
```

Saving asks the seller account to confirm the dataset straight away. Read the
event source to see where it stands:

```json theme={null}
{
  "kind": "event_source",
  "id": "purchase-completed",
  "advertiserId": "42"
}
```

```json theme={null}
{
  "eventSourceId": "purchase-completed",
  "name": "Purchase Completed",
  "sellerAccounts": [
    {
      "accountId": "301",
      "storefront": { "id": "84", "name": "Meta" },
      "sellerId": "1234567890123456",
      "status": "synced",
      "lastSyncedAt": "2026-10-11T14:02:11.000Z",
      "health": null
    }
  ]
}
```

`sellerId` is `null` and `status` is `pending` until the seller account confirms
the object. While the **Conversion events** switch is off for that storefront on
the Connections page, the mapping stays `pending` with a
`SELLER_DATA_SHARING_NOT_PERMITTED` blocker and nothing is checked. Turn the
switch on and Apostra confirms the mapping within about an hour.

### Event types must match

A destination that declares the event types it accepts must accept every type
your source records. A LinkedIn conversion rule records one type, so it maps only
to a source whose `eventTypes` are all on that rule's list. A source with no
`eventTypes` records every type, so it maps only to a destination that declares
none. Meta, Snap and TikTok datasets and pixels accept all types. A mismatch is
refused at save time with `VALIDATION_ERROR` on the entry's `sellerId`. Narrow
the source's `eventTypes`, or map a destination that accepts them.

## Use the source in a campaign goal

Name the event source in an event goal. Use your own `event_source_id`, not the
platform's id:

```json theme={null}
{
  "campaignId": "5501",
  "idempotencyKey": "campaign-5501-goal-2026-10-11-001",
  "optimizationGoals": [
    {
      "kind": "event",
      "event_sources": [
        {
          "event_source_id": "purchase-completed",
          "event_type": "purchase",
          "value_field": "order_total"
        }
      ],
      "attribution_window": { "post_click": { "interval": 7, "unit": "days" } },
      "priority": 1
    }
  ]
}
```

When a media buy on that account is created from this goal, the request Apostra
sends the seller carries the mapped dataset id. Your media buy keeps showing your
own `event_source_id`. Seller-managed sources and a platform's built-in events
are sent unchanged.

### When a buy is refused

A media buy whose goal names an event source that cannot be used on that account
fails before anything reaches the seller. A read of the media buy shows
`errorCode: "invalid_request"`, owned by you (`buyer_input`), and the failure
reason starts with one of the codes below. Fix the cause, then create a new media
buy.

| Code | What it means | Fix |
| - | - | - |
| `SELLER_EVENT_SOURCE_DESTINATION_AMBIGUOUS` | The account has pixels or datasets, and you mapped none for this source | Map one: `sellerAccounts` on `save_event_source`, or **Map** on the Connections page |
| `SELLER_EVENT_SOURCE_DESTINATION_MISSING` | The account has none, or the one you named is not on the account, or does not accept every event type your source records | Create the pixel or dataset in the platform's console and map it, or map one that accepts your source's event types |
| `SELLER_DATA_SHARING_NOT_PERMITTED` | The **Conversion events** switch is off for this storefront | Turn on **Conversion events** for that storefront on the Connections page |
| `SELLER_OBJECT_TYPE_UNSUPPORTED` | This seller cannot take event sources, such as a managed seller agent | Optimize toward a metric instead, or buy from a seller account that can take event sources |

A mapping that is still being confirmed is not a refusal: the buy is held and
sent once the mapping reads `synced`. If a Meta product on the buy sets an
explicit `pixelId` that differs from the dataset you mapped, the buy is refused
for the conflict. Remove the explicit `pixelId` or map the same dataset.

The full list of blocker codes and what each media-buy state does is in
[Measurement and incrementality](/v2/guides/measurement-incrementality#how-a-source-reaches-each-seller-account).

## Map an audience

Map an audience the same way. The audience must already exist: save its members
first, then map it once it appears in the advertiser's audience list:
`get({ "kind": "audience", "advertiserId": "42" })`. An audience read takes
the advertiser, not an audience id, and returns every audience for it, 50 per
page (`audienceOffset` pages on).

```json theme={null}
{
  "advertiserId": "42",
  "audiences": [
    {
      "audienceId": "loyal-customers",
      "sellerAccounts": [
        { "accountId": "301", "sellerId": "23850000000012345" }
      ]
    }
  ]
}
```

An entry that only maps sends no members. Saving asks the seller account to
confirm the audience is there. Read it back with the same listing,
`get({ "kind": "audience", "advertiserId": "42" })`, and find the audience by
`audienceId`; each of its `sellerAccounts[]` entries carries `status`, `sellerId`, and, once confirmed, the seller's own size
and match in `match`:

```json theme={null}
{
  "accountId": "301",
  "storefront": { "id": "84", "name": "Meta" },
  "sellerId": "23850000000012345",
  "status": "synced",
  "blocker": null,
  "lastSyncedAt": "2026-10-11T14:03:40.000Z",
  "match": {
    "matched_count": 48210,
    "effective_match_rate": 0.62
  }
}
```

`match` is `null` until the mapping is confirmed or when the seller reports
nothing. If the audience is not on the account, or the seller reports it
deleted, suspended or failed, the mapping reads `SELLER_AUDIENCE_MISSING`.
Check the id on the Connections page and map the right audience.

## Unmap

To end a mapping, send the account with `unmap: true` instead of a `sellerId`.
This works the same on `save_event_source` and `save_audience`:

```json theme={null}
{
  "advertiserId": "42",
  "idempotencyKey": "unmap-purchase-completed-2026-10-11-002",
  "eventSources": [
    {
      "eventSourceId": "purchase-completed",
      "sellerAccounts": [{ "accountId": "301", "unmap": true }]
    }
  ]
}
```

Unmapping ends Apostra's mapping on that account only. It never deletes or
changes the pixel, dataset or audience on the platform. While a live media buy
uses the mapping, the unmap fails with `INVALID_STATE` and names the media buys;
unmap once they have ended or been canceled. A later media buy on that account
that names the source fails as if it were never mapped.

## Troubleshooting

| What you see | Cause | Fix |
| - | - | - |
| Mapping stays `pending` | The seller account has not confirmed it yet, or the **Conversion events** switch is off for the storefront (`SELLER_DATA_SHARING_NOT_PERMITTED`) | Wait a minute and read again. If the blocker names the switch, turn on **Conversion events** on the Connections page |
| `VALIDATION_ERROR` on `sellerId` when saving | The destination's declared event types do not cover every type your source records | Map a destination that accepts them, or narrow the source's `eventTypes` |
| `REFERENCE_NOT_FOUND` when saving | The `accountId` is not an active connected account of yours, or the audience does not exist yet | Take `accountId` from `get({ "kind": "connection" })`; save the audience's members first |
| `INVALID_STATE` when unmapping | A live media buy uses the mapping | Unmap after the media buys end or are canceled |
| Account shows `status: "failed"` with `SELLER_OBJECT_TYPE_UNSUPPORTED` | The seller cannot take event sources or audiences | Use a seller account that can, or optimize toward a metric |
| An account shows nothing to map | The account has not been read yet, or the seller does not list its objects | Each account is read about once an hour. If the seller will not list, enter the platform id by hand on the Connections page |

## Related

* [Log events](/v2/guides/log-events): send conversions to a registered event source.
* [Measurement and incrementality](/v2/guides/measurement-incrementality): how a source reaches each seller account and every refusal code.
* [Open Media Partners](/v2/buyer/storefronts/tasks/open-connections-page): the Connections page and its account inventory.
* [V3 tool reference](/v2/setup/v3/tool-reference): `save_event_source`, `save_audience`, and the connection inventory read.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.