> For the complete documentation index, see [llms.txt](https://docs.fuul.xyz/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.fuul.xyz/fuul-mcp-server/sending-events.md).

# Sending Events

The Fuul MCP lets you send custom conversion events directly from your AI assistant — the same events you'd send via the API, but without writing code. This is useful for testing your trigger setup, importing historical conversions, or sending events in bulk from a spreadsheet or CSV.

For full details on event payloads and the `args` format, see [Sending Custom Events](/developer-guide/sending-custom-events-through-the-api.md).

## 1. Get your API key

Before sending events, you need a project API key with the right permission:

1. Go to [app.fuul.xyz](https://app.fuul.xyz) and log in
2. Go to **Settings → API Keys → New API Key**
3. Select the **`send:trigger_event`** scope
4. Give it any name and click **Create**

## 2. Add the key to your environment

Add the key to your `.env` file so the MCP can access your project:

```
FUUL_MCP_PROJECT_API_KEY=your_key_here
```

{% hint style="warning" %}
Never pass the key directly in the chat — set it as an environment variable.
{% endhint %}

Then tell Claude where to find it:

> "My Fuul project API key is set as FUUL\_MCP\_PROJECT\_API\_KEY in my environment — use that for sending events"

From this point on, Claude will use it automatically on every event call.

## 3. Send a single event

> "Send a 'trade' event for user 0xABC... with a value of 100 USDC on Ethereum"

Required fields:

| Field                  | Description                                                       |
| ---------------------- | ----------------------------------------------------------------- |
| `name`                 | The trigger's event name — must match exactly (case-sensitive)    |
| `user_identifier`      | The user's wallet address or email                                |
| `user_identifier_type` | `evm_address`, `solana_address`, `stellar_address`, `email`, etc. |
| `dedup_id`             | A unique ID for this event — used to prevent duplicates           |

{% hint style="info" %}
The `dedup_id` is critical: if you send the same event twice with the same `dedup_id`, the second call returns a 409 and the event is not recorded again. Always use a unique identifier (e.g. a transaction hash or a UUID tied to the source record).
{% endhint %}

Rate limit: **100 requests/minute**.

## 4. Send events in bulk

> "Send these 50 events from this CSV"

The MCP can send up to **100 events per batch call**. Duplicate `dedup_id` values within the batch are silently skipped — the response tells you how many events were actually ingested.

{% hint style="info" %}
Rate limit: **10 requests/minute**.
{% endhint %}

## 5. Check if an event was processed

After sending, you can verify that an event was received and processed:

> "Did user 0xABC... trigger the 'trade' event?"

{% hint style="info" %}
Use this before resending a single event to avoid a 409 duplicate error — if it already exists, don't send it again.
{% endhint %}

## 6. Trace the full pipeline

To see exactly what happened downstream — trigger execution, attribution, payout, and balance movement — provide the `dedup_id` and event name:

> "Show me the full pipeline for the last event I sent"

This returns:

| Field                | Description                                                             |
| -------------------- | ----------------------------------------------------------------------- |
| `trigger_executions` | Whether the trigger fired and its status (`Accepted`, `Rejected`, etc.) |
| `attributions`       | Which conversion was matched and whether it was confirmed               |
| `payouts`            | Amounts and currencies credited                                         |
| `movements`          | The resulting balance changes                                           |

{% hint style="info" %}
Use this when an event was received but rewards didn't appear — it shows exactly where in the pipeline things stopped.
{% endhint %}
