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

# Sending Conversion Events to Meta via the API

> Upload conversion events to Narrative and send them to a Meta dataset through Meta's Conversions API, testing first with a test event code

This guide shows you how to build an unattended integration that uploads conversion events to Narrative and sends them to a Meta dataset (pixel) through Meta's Conversions API. The examples send offline events, such as in-store purchases.

Before you start, complete the [prerequisites](/guides/connector-apis/meta#prerequisites) and [set up API access](/guides/connector-apis/meta#set-up-api-access). You need a profile ID and the numeric ID of the Meta dataset, which [List your Meta datasets](/guides/connector-apis/meta#list-your-meta-datasets) returns.

## 1. Create the dataset

A conversion-event dataset needs two columns:

* `meta_conversion_event`, an object holding the event
* at least one identifier Meta can match on, such as `sha256_hashed_email`

```bash theme={null}
curl -X POST https://api.narrative.io/datasets \
  -H "Authorization: Bearer $NIO_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "store_purchases_meta",
    "display_name": "Store Purchases (Meta)",
    "description": "Offline purchases for Meta",
    "write_mode": "append",
    "schema": {
      "file_config": { "type": "json", "normalize_field_names": false },
      "type": "object",
      "properties": {
        "meta_conversion_event": {
          "type": "object",
          "properties": {
            "meta_dataset_id": { "type": "long" },
            "event_id":        { "type": "string" },
            "event_name":      { "type": "string" },
            "event_timestamp": { "type": "timestamptz" },
            "source":          { "type": "string" },
            "custom_data": {
              "type": "object",
              "properties": {
                "value":    { "type": "double" },
                "currency": { "type": "string" },
                "order_id": { "type": "string" }
              }
            }
          }
        },
        "sha256_hashed_email": {
          "type": "object",
          "properties": { "value": { "type": "string" } }
        }
      }
    }
  }'
```

Every event needs `meta_dataset_id`, `event_id`, `event_name`, `event_timestamp`, and `source`. [The `meta_conversion_event` attribute](/reference/connectors/meta-conversions-api#the-meta_conversion_event-attribute) lists the optional fields, such as `source_url`, `data_processing_options`, more `custom_data` fields, and `store_data`. Add the ones you use to the schema before you activate it, because activation locks the schema.

Record the `id` in the response, then activate the dataset:

```bash theme={null}
curl -X POST https://api.narrative.io/datasets/{dataset_id}/activate \
  -H "Authorization: Bearer $NIO_API_TOKEN"
```

## 2. Confirm Meta accepts the dataset

```bash theme={null}
curl -s "https://api.narrative.io/datasets/{dataset_id}/interfaces?tags=capi" \
  -H "Authorization: Bearer $NIO_API_TOKEN"
# → {"dataset_id": 12347, "accepted": [{"app_id": 8, "interface_id": "conversion_events"}], ...}
```

Look for `"app_id": 8` with `conversion_events` in the `accepted` list. If it is missing, the dataset lacks one of the two columns from step 1.

## 3. Get a test event code

Send test events first, so you can watch them arrive before they count as real conversions:

<Steps>
  <Step title="Open the dataset in Events Manager">
    In Meta Events Manager, open the dataset you are sending to and choose **Test events**.
  </Step>

  <Step title="Choose the channel">
    Select the **Offline** channel and expand **Confirm your server's events are set up correctly**.
  </Step>

  <Step title="Copy the code">
    Copy the test event code Meta shows, which starts with `TEST`. Keep the tab open while you test.
  </Step>
</Steps>

## 4. Create the connection

```bash theme={null}
curl -X POST https://api.narrative.io/v2/connections \
  -H "Authorization: Bearer $NIO_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "connections_dataset",
    "dataset_id": 12347,
    "profile_id": "<PROFILE_ID>",
    "quick_settings": {
      "type": "conversion_events",
      "test_event_code": "<TEST_EVENT_CODE>",
      "historical_data_enabled": true
    }
  }'
# → 201 {"type": "connections_dataset", "id": "<CONNECTION_ID>",
#        "app": {"id": 8, "name": "Facebook Connector"},
#        "quick_settings": {"type": "conversion_events", "test_event_code": "<TEST_EVENT_CODE>",
#                           "historical_data_enabled": true},
#        "status": "active", ...}
```

The connection names no Meta dataset. Each event names its own in `meta_dataset_id`, so one connection can send to every Meta dataset the profile can reach.

`historical_data_enabled` set to `true` sends the events already in the dataset as well as new ones. Set it to `false` to send only events written after the connection exists.

## 5. Upload events

Each line of the file is one event. `event_name` takes the lowercase names listed in [Event names](/reference/connectors/meta-conversions-api#event-names), such as `purchase`. Offline events use `physical_store` as `source`.

```json theme={null}
{"meta_conversion_event": {"meta_dataset_id": <META_DATASET_ID>, "event_id": "order-1008", "event_name": "purchase", "event_timestamp": "2026-10-03T14:02:36Z", "source": "physical_store", "custom_data": {"value": 2.08, "currency": "USD", "order_id": "order-1008"}}, "sha256_hashed_email": {"value": "<SHA-256 of the trimmed, lowercased email>"}}
```

Upload and ingest the file the same way as an audience file (see [Upload and ingest your file](/guides/connector-apis/meta/audiences-api#3-upload-and-ingest-your-file)):

```bash theme={null}
curl -X POST https://api.narrative.io/uploads/store-purchases.jsonl \
  -H "Authorization: Bearer $NIO_API_TOKEN"
# → {"path": "<UPLOAD_PATH>", "url": "https://...", "expiry": "..."}

curl -X PUT "<url from the response>" --upload-file ./store-purchases.jsonl

curl -X POST https://api.narrative.io/datasets/{dataset_id}/upload \
  -H "Authorization: Bearer $NIO_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"source_file": "<UPLOAD_PATH>"}'
```

## 6. Check the events at Meta

Watch the **Test events** tab you left open. Within a few minutes each event appears with its event name (for example **Purchase**), status **Processed**, and **Server** as where it was received from. Expand an event to see its value, currency, `order_id`, action source, and the user data keys Meta matched on, such as **Email**.

To hear about deliveries in your integration, subscribe to [delivery notifications](/guides/connector-apis/meta#delivery-notifications).

## Going live

When the test events look right, send real conversions:

1. Create a connection on the dataset with the same request as step 4, leaving out `test_event_code`.
2. Delete the test connection with `DELETE /v2/connections/{connection_id}`.

Events sent through the new connection count as real conversions.

## Keeping events flowing

Write new events to the dataset. The connection keeps running, so new rows reach Meta without further calls. Meta accepts offline events up to 90 days old and other events up to 7 days old. See [Event age limits](/reference/connectors/meta-conversions-api#event-age-limits).

## Stopping delivery

```bash theme={null}
curl -X DELETE https://api.narrative.io/v2/connections/{connection_id} \
  -H "Authorization: Bearer $NIO_API_TOKEN"
# → 200 {}
```

Deleting the connection archives it and stops further events from reaching Meta.

## Troubleshooting

| Symptom | Cause | Fix |
| - | - | - |
| `400 Dataset Schema Incompatible with Connector` with `required property 'meta_conversion_event' not found` | The dataset has no `meta_conversion_event` column | Create a new dataset with the schema in step 1 |

## Getting help

Contact your Narrative relationship manager with your company ID, the dataset ID, and the failing request and response.

***

## Related content

<CardGroup cols={2}>
  <Card title="Delivering Custom Audiences via the API" icon="users" href="/guides/connector-apis/meta/audiences-api">
    Deliver hashed identifiers into a Custom Audience
  </Card>

  <Card title="Meta Conversions API Connector" icon="meta" href="/reference/connectors/meta-conversions-api">
    Every `meta_conversion_event` field, event name, and action source
  </Card>

  <Card title="Connector Interfaces" icon="plug" href="/concepts/data-activation/connector-interfaces">
    Why a dataset connects to an interface rather than a connector
  </Card>

  <Card title="API Keys" icon="key" href="/account-settings/api-keys">
    Create and rotate keys for programmatic access
  </Card>
</CardGroup>


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