---
title: Send an event
description: Send a push notification event via Trigv. Request fields, cURL and Laravel examples, and response codes.
---
<div>
  POST
  /api/v1/events
</div>

# Send an event

Ingest a notification event for a workspace channel. Trigv validates the API key and channel, increments the workspace monthly usage counter, queues push delivery to subscribed devices, and returns event metadata. Use `idempotency_key` to safely retry without double-counting.

## Request

**URL:** `https://api.trigv.com/api/v1/events`

**Headers:**

```
Content-Type: application/json
Accept: application/json
Authorization: Bearer trgv_xxxxxxxx_yyyyyyyyyyyyyyyyyyyyyyyyyyyy
```

### Body parameters (JSON)

<table class="ti-table">
  <thead>
    <tr><th>Parameter</th><th>Type</th><th>Required</th><th>Description</th></tr>
  </thead>
  <tbody>
    <tr><td><code>channel</code></td><td>string</td><td>Yes</td><td>Channel slug in your workspace (e.g. <code>general</code>). Max 120 chars. Case-sensitive.</td></tr>
    <tr><td><code>title</code></td><td>string</td><td>Yes</td><td>Notification headline. Max 255 characters.</td></tr>
    <tr><td><code>description</code></td><td>string</td><td>No</td><td>Secondary body text. Max 1000 characters. If omitted, the push body uses <code>title</code>.</td></tr>
    <tr><td><code>icon</code></td><td>string</td><td>No</td><td><strong>Rejected.</strong> Put emoji in <code>title</code> if you want it on the push banner.</td></tr>
    <tr><td><code>image_url</code></td><td>string (URL)</td><td>No</td><td>HTTPS image URL passed through to your devices. Max 2048 characters. <strong>Not stored on Trigv servers.</strong> The app fetches the image locally; links may expire after delivery.</td></tr>
    <tr><td><code>url</code></td><td>string (URL)</td><td>No</td><td>Optional destination link. Max 2048 characters. Passed through in push data; <strong>not stored on Trigv servers.</strong></td></tr>
    <tr><td><code>level</code></td><td>string</td><td>No</td><td>One of <code>info</code>, <code>success</code>, <code>warning</code>, <code>error</code>. Default: <code>info</code>. Affects in-app styling only.</td></tr>
    <tr><td><code>delivery_urgency</code></td><td>string</td><td>No</td><td><code>standard</code> (default) or <code>time_sensitive</code>. On iOS, <code>time_sensitive</code> can break through Focus when allowed.</td></tr>
    <tr><td><code>event_type</code></td><td>string</td><td>No</td><td>Machine-readable type (e.g. <code>deploy.complete</code>). Max 120 characters.</td></tr>
    <tr><td><code>idempotency_key</code></td><td>string</td><td>No</td><td>Stable key for retries. Duplicate requests return <code>200</code> with the original event and do not increment usage again.</td></tr>
    <tr><td><code>api_key</code></td><td>string</td><td>No</td><td><strong>Rejected.</strong> Use <code>Authorization: Bearer</code> instead.</td></tr>
  </tbody>
</table>

## Code examples

### cURL

```
curl -X POST https://api.trigv.com/api/v1/events \
		-H "Content-Type: application/json" \
		-H "Accept: application/json" \
		-H "Authorization: Bearer trgv_abcd1234_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
		-d '{
			"channel": "general",
			"title": "✅ Database backup complete",
			"description": "Cron finished in 4.2 seconds.",
			"level": "success",
			"delivery_urgency": "time_sensitive",
			"event_type": "backup.complete"
		}'
```

### Laravel / PHP

```
use Illuminate\Support\Facades\Http;

$response = Http::withToken(config('services.trigv.api_key'))
		->post('https://api.trigv.com/api/v1/events', [
			'channel' => 'general',
			'title' => 'App exploded 💥',
			'description' => 'Fatal error in OrderController.php:42',
			'level' => 'error',
			'idempotency_key' => 'order-job-'.now()->format('Y-m-d-H'),
		]);
```

## Responses

<div>
  <div>
    202 Accepted
    <p>New event queued for push delivery.</p>
    
```
{
		"event": {
			"public_id": "evt_01JXXXXXXXX",
			"event_uuid": "550e8400-e29b-41d4-a716-446655440000",
			"status": "queued",
			"level": "success",
			"event_type": "backup.complete",
			"target_device_count": 2,
			"received_at": "2026-06-06T12:00:00+00:00"
		}
}
```

  </div>
  <div>
    200 OK
    <p>Duplicate <code>idempotency_key</code> - same event returned, usage not incremented again.</p>
  </div>
  <div>
    422 Unprocessable
    <p>Missing or invalid fields (e.g. <code>channel</code>, <code>title</code>).</p>
    
```
{
		"message": "The channel field is required. (and 1 more error)",
		"errors": {
			"channel": ["The channel field is required."],
			"title": ["The title field is required."]
		}
}
```

  </div>
  <div>
    404 Not Found
    <p>Unknown or inactive channel slug for this workspace.</p>
    
```
{ "message": "Channel not found." }
```

  </div>
</div>

More examples: [Guides](/docs/learn) · [Errors & rate limits](/docs/errors)
