Bruno API collection for testing the EmitKit Events API v1.
The complete API specification is available in OpenAPI 3.1 format:
- JSON Format: http://localhost:5173/api/openapi.json
- YAML Format: http://localhost:5173/api/openapi.yaml
- Source File:
../openapi/openapi.yaml
Use these URLs with tools like:
- Mintlify (Auto-import for documentation)
- Postman (Import → Link)
- Insomnia (Import → URL)
- SDK Generators (e.g.,
@hey-api/openapi-ts) - API Testing tools
- OpenAPI Specification
- Setup
- Environments
- Available Requests
- API Reference
- Authentication
- Channel Auto-Creation
- Rate Limiting
- Idempotency
- Best Practices
- Migration from v0 API
-
Install Bruno: Download from usebruno.com
-
Open Collection: File → Open Collection → Select the
brunodirectory -
Configure Environment:
- Select either
DevelopmentorProductionenvironment - Set the
api_keysecret variable:- Click the environment dropdown
- Click "Configure"
- Enter your API key (format:
emitkit_xxxxxxxxxxxxxxxxxxxxx)
- Select either
- API URL:
http://localhost:5173/api/v1 - Use this for local development
- API URL:
https://useblip.dev/api/v1 - Use this for testing against production
File: Track.bru
Simple event creation with commonly used fields. Good for quick testing.
Fields included:
channelNametitledescriptioniconnotify
File: Create Event - Full.bru
Demonstrates all available fields in the Events API.
Fields included:
channelNametitledescriptionicontagsmetadata(custom object)userIdnotifysource
File: Create Event - Payment.bru
Real-world example for tracking payment events.
Use case: Payment notifications, subscription upgrades
File: Create Event - Minimal.bru
Minimum required fields only (channelName + title).
Use case: Quick system logs, simple notifications
File: Create Event - User Signup.bru
Real-world example for tracking user registrations.
Use case: User onboarding, signup tracking
- Select a request
- Click "Send"
- View response in the right panel
- Right-click on the collection name
- Select "Run Collection"
- Optionally filter by tags (e.g., only run
paymentrequests)
Requests are tagged for easy filtering during collection runs:
events- All event-related requestsv1- API versionpayment,signup, etc. - Use case specific tags
POST /api/v1/events
API endpoint for creating events with automatic channel management.
Authorization: Bearer <your-api-key>
Content-Type: application/json
{
channelName: string; // Auto-creates if doesn't exist
title: string; // Event title
description?: string; // Optional description
icon?: string; // Optional icon (emoji)
tags?: string[]; // Optional tags
metadata?: Record<string, JSONValue>; // Optional custom metadata
userId?: string | null; // Optional user ID
notify?: boolean; // Send notification (default: true)
source?: string; // Source identifier
}curl -X POST https://your-domain.com/api/v1/events \
-H "Authorization: Bearer emitkit_xxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"channelName": "payments",
"title": "Payment Received",
"description": "User upgraded to Pro plan",
"icon": "💰",
"tags": ["payment", "upgrade"],
"metadata": {
"amount": 99.99,
"plan": "pro",
"userId": "user_123"
},
"notify": true
}'Status: 201 Created
{
"success": true,
"data": {
"id": "event_xxxxxxxxxxxxxxxxxxxxx",
"channelId": "channel_xxxxxxxxxxxxxxxxxxxxx",
"channelName": "payments",
"title": "Payment Received",
"createdAt": "2025-01-15T10:30:00.000Z"
}
}Status: 400 Bad Request
{
"success": false,
"error": "Validation error",
"details": [
{
"code": "invalid_type",
"expected": "string",
"received": "undefined",
"path": ["channelName"],
"message": "Required"
}
]
}Status: 401 Unauthorized
{
"success": false,
"error": "Unauthorized"
}Status: 500 Internal Server Error
{
"success": false,
"error": "Failed to create event"
}All requests must include a valid API key in the Authorization header:
Authorization: Bearer emitkit_xxxxxxxxxxxxxxxxxxxxx
The API key automatically scopes requests to:
- Organization: Extracted from API key metadata
- Site: Extracted from API key metadata
When you send an event to a channel that doesn't exist, it will be automatically created within your site with:
- Name: The
channelNameyou specified - Icon: The
iconfrom the event (if provided) - Description: The
descriptionfrom the event (if provided)
This allows you to start sending events immediately without pre-creating channels.
API keys have built-in rate limiting:
- Default: 100 requests per minute
- Rate limits are configurable per API key
- When rate limited, you'll receive a
429 Too Many Requestsresponse
Rate limit information is returned in response headers:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1733270400
To prevent duplicate events from retries or webhook replays, include an Idempotency-Key header:
curl -X POST https://api.emitkit.com/v1/events \
-H "Authorization: Bearer emitkit_xxxxx" \
-H "Idempotency-Key: payment-123-retry-1" \
-H "Content-Type: application/json" \
-d '{"channelName": "payments", "title": "Payment Received"}'How it works:
- First request with a key: Event created, response cached for 24 hours
- Subsequent requests with same key: Returns cached response immediately
- Cached responses include
X-Idempotent-Replay: trueheader - Idempotency keys are scoped to your organization
When to use:
- Payment webhooks (prevent double-charging)
- Network retry logic (safe retries)
- Webhook replays from third-party services
-
Channel Names: Use consistent, kebab-case names (e.g.,
user-signups,payment-received)- ✅
user-signups,payment-received - ❌
UserSignups,payment_received
- ✅
-
Icons: Use single emoji characters for better display
- ✅
🚀,💰,👋 - ❌
:rocket:, multiple emojis
- ✅
-
Metadata: Keep metadata JSON-serializable and avoid deeply nested objects
-
Error Handling: Always check the
successfield in responses -
Request IDs: Every response includes a
requestIdfield - save this for debugging and support tickets
If you're upgrading from the previous API:
{
"channelId": "channel_xxx",
"organizationId": "org_xxx",
"title": "Event Title"
}{
"channelName": "my-channel",
"title": "Event Title"
}Key Changes:
- No need to specify
channelId- usechannelNameinstead - No need to specify
organizationId- extracted from API key - Channels are auto-created if they don't exist
- API key required in
Authorizationheader