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

# Triggering Events

> Learn how to trigger events from your application using the SDK or HTTP API.

# Triggering Events

Trigger events from your application to start workflows. You can use the official Node.js SDK or make HTTP requests from any programming language.

## Using the SDK

The Flowripple SDK provides a simple, type-safe way to trigger events from Node.js applications.

### Installation

<CodeGroup>
  ```bash npm theme={null}
  npm install @flowripple/sdk
  ```

  ```bash pnpm theme={null}
  pnpm add @flowripple/sdk
  ```

  ```bash yarn theme={null}
  yarn add @flowripple/sdk
  ```

  ```bash bun theme={null}
  bun add @flowripple/sdk
  ```
</CodeGroup>

### Initialization

```typescript theme={null}
import { FlowrippleClient } from '@flowripple/sdk';

const flowripple = new FlowrippleClient({
  apiKey: process.env.FLOWRIPPLE_API_KEY
});
```

### Configuration Options

| Option    | Type    | Required | Description                                              |
| --------- | ------- | -------- | -------------------------------------------------------- |
| `apiKey`  | string  | Yes      | Your API key (starts with `frp_`)                        |
| `baseUrl` | string  | No       | Custom API URL. Defaults to `https://api.flowripple.com` |
| `silent`  | boolean | No       | If `true`, errors return `false` instead of throwing     |
| `version` | string  | No       | API version. Defaults to `v1`                            |

```typescript theme={null}
const flowripple = new FlowrippleClient({
  apiKey: 'frp_your-api-key',
  baseUrl: 'https://api.flowripple.com',
  silent: false,
  version: 'v1'
});
```

### Basic Trigger

```typescript theme={null}
await flowripple.trigger('user.signup', {
  userId: 'usr_123',
  email: 'user@example.com',
  name: 'John Doe'
});
```

The `trigger` method accepts:

* **identifier** (string): The event identifier (e.g., `user.signup`)
* **data** (object, optional): JSON payload with event data
* **options** (object, optional): Trigger options including idempotency key

### Idempotent Requests

Use idempotency keys to safely retry requests without creating duplicate events. This is useful when network issues occur or you need to ensure exactly-once processing.

```typescript theme={null}
await flowripple.trigger('order.created', {
  orderId: 'ord_456',
  amount: 99.99
}, {
  idempotencyKey: 'order-ord_456-creation'
});
```

**Key scoping:** Idempotency keys are scoped per event identifier. This means:

* `user.signup` with key `abc123` and `order.created` with key `abc123` are independent
* The same key can be reused across different event types

**Key requirements:**

* Maximum 256 characters
* Alphanumeric characters, hyphens (`-`), underscores (`_`), colons (`:`), and periods (`.`) allowed

<Tip>
  Use a unique value tied to your business logic, such as combining the entity type and ID (e.g., `order-ord_456-creation`). This ensures retries are safe while allowing different operations to proceed independently.
</Tip>

When a request with an idempotency key matches a previous request:

* The cached response is returned immediately
* No duplicate event is created
* The response includes `cached: true` to indicate it was served from cache

Cached responses are stored for **24 hours**.

### Error Handling

By default, failed triggers throw an error:

```typescript theme={null}
try {
  await flowripple.trigger('user.signup', { userId: 'usr_123' });
} catch (error) {
  console.error('Failed to trigger event:', error.message);
}
```

### Silent Mode

Enable silent mode to return `false` on failure instead of throwing:

```typescript theme={null}
const flowripple = new FlowrippleClient({
  apiKey: process.env.FLOWRIPPLE_API_KEY,
  silent: true
});

const result = await flowripple.trigger('user.signup', { userId: 'usr_123' });

if (result === false) {
  console.log('Event trigger failed silently');
}
```

<Tip>
  Use silent mode in non-critical paths where you don't want event failures to interrupt your application flow.
</Tip>

## Using the HTTP API

Trigger events from any programming language using HTTP requests.

### Endpoint

```
POST https://api.flowripple.com/api/v1/trigger
```

### Headers

| Header         | Value              |
| -------------- | ------------------ |
| `Content-Type` | `application/json` |
| `x-api-key`    | Your API key       |

### Request Body

```json theme={null}
{
  "identifier": "user.signup",
  "data": {
    "userId": "usr_123",
    "email": "user@example.com",
    "name": "John Doe"
  },
  "idempotencyKey": "signup-usr_123"
}
```

| Field            | Type   | Required | Description                                                               |
| ---------------- | ------ | -------- | ------------------------------------------------------------------------- |
| `identifier`     | string | Yes      | Event identifier                                                          |
| `data`           | object | No       | Event payload                                                             |
| `idempotencyKey` | string | No       | Unique key for idempotent requests (max 256 chars, alphanumeric + `-_:.`) |

### Response

**Success (200)**

```json theme={null}
{
  "success": true,
  "jobId": "job_abc123",
  "message": "Event queued for processing"
}
```

**Success - Cached (200)**

When using an idempotency key that matches a previous request:

```json theme={null}
{
  "success": true,
  "jobId": "job_abc123",
  "message": "Event queued for processing",
  "cached": true
}
```

**Error (4xx/5xx)**

```json theme={null}
{
  "error": "Event trigger failed",
  "message": "Invalid API key"
}
```

## Code Examples

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.flowripple.com/api/v1/trigger \
    -H "Content-Type: application/json" \
    -H "x-api-key: YOUR_API_KEY" \
    -d '{
      "identifier": "user.signup",
      "data": {
        "userId": "usr_123",
        "email": "user@example.com",
        "name": "John Doe"
      },
      "idempotencyKey": "signup-usr_123"
    }'
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      'https://api.flowripple.com/api/v1/trigger',
      headers={
          'Content-Type': 'application/json',
          'x-api-key': 'YOUR_API_KEY'
      },
      json={
          'identifier': 'user.signup',
          'data': {
              'userId': 'usr_123',
              'email': 'user@example.com',
              'name': 'John Doe'
          },
          'idempotencyKey': 'signup-usr_123'
      }
  )

  print(response.json())
  ```

  ```go Go theme={null}
  package main

  import (
      "bytes"
      "encoding/json"
      "net/http"
  )

  func main() {
      payload := map[string]interface{}{
          "identifier": "user.signup",
          "data": map[string]string{
              "userId": "usr_123",
              "email":  "user@example.com",
              "name":   "John Doe",
          },
      }

      body, _ := json.Marshal(payload)

      req, _ := http.NewRequest(
          "POST",
          "https://api.flowripple.com/api/v1/trigger",
          bytes.NewBuffer(body),
      )
      req.Header.Set("Content-Type", "application/json")
      req.Header.Set("x-api-key", "YOUR_API_KEY")

      client := &http.Client{}
      resp, _ := client.Do(req)
      defer resp.Body.Close()
  }
  ```

  ```ruby Ruby theme={null}
  require 'net/http'
  require 'json'

  uri = URI('https://api.flowripple.com/api/v1/trigger')

  http = Net::HTTP.new(uri.host, uri.port)
  http.use_ssl = true

  request = Net::HTTP::Post.new(uri.path)
  request['Content-Type'] = 'application/json'
  request['x-api-key'] = 'YOUR_API_KEY'
  request.body = {
    identifier: 'user.signup',
    data: {
      userId: 'usr_123',
      email: 'user@example.com',
      name: 'John Doe'
    }
  }.to_json

  response = http.request(request)
  puts response.body
  ```

  ```php PHP theme={null}
  <?php

  $curl = curl_init();

  curl_setopt_array($curl, [
      CURLOPT_URL => 'https://api.flowripple.com/api/v1/trigger',
      CURLOPT_RETURNTRANSFER => true,
      CURLOPT_POST => true,
      CURLOPT_HTTPHEADER => [
          'Content-Type: application/json',
          'x-api-key: YOUR_API_KEY'
      ],
      CURLOPT_POSTFIELDS => json_encode([
          'identifier' => 'user.signup',
          'data' => [
              'userId' => 'usr_123',
              'email' => 'user@example.com',
              'name' => 'John Doe'
          ]
      ])
  ]);

  $response = curl_exec($curl);
  curl_close($curl);

  echo $response;
  ```
</CodeGroup>

## Auto-Creation on First Trigger

When you trigger an event identifier that doesn't exist, Flowripple automatically creates the event:

```typescript theme={null}
// This creates "order.refunded" if it doesn't exist
await flowripple.trigger('order.refunded', {
  orderId: 'ord_456',
  amount: 99.99,
  reason: 'customer_request'
});
```

The auto-created event:

* Uses the identifier as the event name
* Extracts variables from the payload
* Appears in your dashboard immediately

<Note>
  Auto-creation is convenient for development. For production, consider pre-creating events in the dashboard to define expected payload structures.
</Note>

## Best Practices

<AccordionGroup>
  <Accordion title="Store API keys securely">
    Never hardcode API keys in your source code. Use environment variables or a secrets manager:

    ```typescript theme={null}
    // Good
    const flowripple = new FlowrippleClient({
      apiKey: process.env.FLOWRIPPLE_API_KEY
    });

    // Bad - never do this
    const flowripple = new FlowrippleClient({
      apiKey: 'frp_abc123...'
    });
    ```
  </Accordion>

  <Accordion title="Handle trigger failures gracefully">
    Decide how your application should behave if an event trigger fails:

    ```typescript theme={null}
    // Option 1: Log and continue (non-critical events)
    const flowripple = new FlowrippleClient({
      apiKey: process.env.FLOWRIPPLE_API_KEY,
      silent: true
    });

    // Option 2: Throw and handle (critical events)
    try {
      await flowripple.trigger('payment.completed', data);
    } catch (error) {
      // Log to monitoring service
      // Maybe retry or queue for later
    }
    ```
  </Accordion>

  <Accordion title="Send consistent payloads">
    Always send the same fields for a given event type:

    ```typescript theme={null}
    // Create a helper to ensure consistency
    function triggerUserSignup(user: User) {
      return flowripple.trigger('user.signup', {
        userId: user.id,
        email: user.email,
        name: user.name || 'Unknown',
        createdAt: new Date().toISOString()
      });
    }
    ```
  </Accordion>

  <Accordion title="Use separate keys per environment">
    Create different API keys for development, staging, and production to isolate environments and manage access.
  </Accordion>

  <Accordion title="Use idempotency keys for critical events">
    For important events like payments or order creation, always use idempotency keys to prevent duplicates:

    ```typescript theme={null}
    // Generate a unique key based on business logic
    const idempotencyKey = `payment-${paymentId}-${Date.now()}`;

    await flowripple.trigger('payment.completed', {
      paymentId,
      amount,
      customerId
    }, {
      idempotencyKey
    });
    ```

    Good idempotency key patterns:

    * `order-{orderId}-creation` - for order events
    * `payment-{paymentId}-{timestamp}` - for payment events
    * `user-{userId}-signup` - for one-time user events
  </Accordion>
</AccordionGroup>

## What's Next?

<CardGroup cols={2}>
  <Card title="Monitoring Captures" icon="chart-line" href="/events/monitoring-captures">
    Track triggered events and analyze capture data.
  </Card>

  <Card title="Quickstart Guide" icon="rocket" href="/quickstart">
    Complete end-to-end guide for your first workflow.
  </Card>
</CardGroup>
