Event Types API

Event types define the categories of events your application sends via webhooks. Use this API to create, manage, and organize event types with optional JSON schemas for validation.

The Event Type Object

Event types are named categories that endpoints can subscribe to. Each event type optionally includes a JSON schema for payload validation.

Attributes

idstring
Unique identifier for the event type (KSUID format)
org_idstring
Organization that owns this event type
namestring
Event type name in resource.action format (lowercase, past tense)
descriptionstring | null
Human-readable description of when this event fires
schemaobject | null
Optional JSON Schema for payload validation
subscriber_countinteger
Number of endpoints subscribed to this event type
created_atstring
ISO 8601 timestamp when the event type was created
updated_atstring
ISO 8601 timestamp when the event type was last updated
Example Event Type Object
{
  "id": "evt_2Zy3X8a9b0c1d2e3f4g5h6i7",
  "org_id": "org_xyz789",
  "name": "user.created",
  "description": "Fired when a new user account is created",
  "schema": {
    "type": "object",
    "properties": {
      "user_id": { "type": "string" },
      "email": { "type": "string", "format": "email" },
      "created_at": { "type": "string", "format": "date-time" }
    },
    "required": ["user_id", "email", "created_at"]
  },
  "subscriber_count": 12,
  "created_at": "2026-01-15T10:30:00Z",
  "updated_at": "2026-01-15T10:30:00Z"
}

Create an Event Type

Define a new event type with an optional JSON schema for payload validation.

POST /v1/event-types

Parameters

FieldTypeDescription
namestringrequiredEvent type name (lowercase.dot.notation)
descriptionstringHuman-readable description
schemaobjectJSON Schema for validation
Node.js
import fetch from 'node-fetch';

const response = await fetch('https://api.hookmesh.com/v1/event-types', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.HOOKMESH_API_KEY}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    name: 'payment.succeeded',
    description: 'Fired when a payment is successfully processed',
    schema: {
      type: 'object',
      properties: {
        payment_id: { type: 'string' },
        amount: { type: 'number', minimum: 0 },
        currency: { type: 'string', pattern: '^[A-Z]{3}$' },
        customer_id: { type: 'string' }
      },
      required: ['payment_id', 'amount', 'currency', 'customer_id']
    }
  })
});

const eventType = await response.json();
console.log('Event type created:', eventType.id);
Python
import requests
import os

response = requests.post(
    'https://api.hookmesh.com/v1/event-types',
    headers={
        'Authorization': f'Bearer {os.environ["HOOKMESH_API_KEY"]}',
        'Content-Type': 'application/json'
    },
    json={
        'name': 'payment.succeeded',
        'description': 'Fired when a payment is successfully processed',
        'schema': {
            'type': 'object',
            'properties': {
                'payment_id': {'type': 'string'},
                'amount': {'type': 'number', 'minimum': 0},
                'currency': {'type': 'string', 'pattern': '^[A-Z]{3}$'},
                'customer_id': {'type': 'string'}
            },
            'required': ['payment_id', 'amount', 'currency', 'customer_id']
        }
    }
)

event_type = response.json()
print(f'Event type created: {event_type["id"]}')
Go
package main

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

type EventTypeRequest struct {
    Name        string                 `json:"name"`
    Description string                 `json:"description"`
    Schema      map[string]interface{} `json:"schema"`
}

func main() {
    payload := EventTypeRequest{
        Name:        "payment.succeeded",
        Description: "Fired when a payment is successfully processed",
        Schema: map[string]interface{}{
            "type": "object",
            "properties": map[string]interface{}{
                "payment_id":  map[string]string{"type": "string"},
                "amount":      map[string]interface{}{"type": "number", "minimum": 0},
                "currency":    map[string]string{"type": "string", "pattern": "^[A-Z]{3}$"},
                "customer_id": map[string]string{"type": "string"},
            },
            "required": []string{"payment_id", "amount", "currency", "customer_id"},
        },
    }

    body, _ := json.Marshal(payload)
    req, _ := http.NewRequest("POST", "https://api.hookmesh.com/v1/event-types", bytes.NewBuffer(body))
    req.Header.Set("Authorization", "Bearer "+os.Getenv("HOOKMESH_API_KEY"))
    req.Header.Set("Content-Type", "application/json")

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()

    var eventType map[string]interface{}
    json.NewDecoder(resp.Body).Decode(&eventType)
    fmt.Printf("Event type created: %s\n", eventType["id"])
}
PHP
<?php

$ch = curl_init('https://api.hookmesh.com/v1/event-types');

curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('HOOKMESH_API_KEY'),
        'Content-Type: application/json'
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'name' => 'payment.succeeded',
        'description' => 'Fired when a payment is successfully processed',
        'schema' => [
            'type' => 'object',
            'properties' => [
                'payment_id' => ['type' => 'string'],
                'amount' => ['type' => 'number', 'minimum' => 0],
                'currency' => ['type' => 'string', 'pattern' => '^[A-Z]{3}$'],
                'customer_id' => ['type' => 'string']
            ],
            'required' => ['payment_id', 'amount', 'currency', 'customer_id']
        ]
    ])
]);

$response = curl_exec($ch);
$eventType = json_decode($response, true);

echo "Event type created: {$eventType['id']}\n";

curl_close($ch);

List Event Types

Retrieve all event types for your organization, optionally filtered by name.

GET /v1/event-types

Query Parameters

ParameterTypeDescription
limitintegerNumber of results per page (default: 20, max: 100)
cursorstringPagination cursor from previous response
searchstringFilter by event type name (partial match)
Node.js
const response = await fetch(
  'https://api.hookmesh.com/v1/event-types?limit=50&search=payment',
  {
    headers: {
      'Authorization': `Bearer ${process.env.HOOKMESH_API_KEY}`
    }
  }
);

const { data, next_cursor } = await response.json();
console.log(`Found ${data.length} event types`);
Python
response = requests.get(
    'https://api.hookmesh.com/v1/event-types',
    headers={'Authorization': f'Bearer {os.environ["HOOKMESH_API_KEY"]}'},
    params={'limit': 50, 'search': 'payment'}
)

result = response.json()
print(f'Found {len(result["data"])} event types')
Go
package main

import (
    "encoding/json"
    "fmt"
    "net/http"
    "os"
)

func main() {
    req, _ := http.NewRequest("GET",
        "https://api.hookmesh.com/v1/event-types?limit=50&search=payment",
        nil)

    req.Header.Set("Authorization", "Bearer "+os.Getenv("HOOKMESH_API_KEY"))

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()

    var result map[string]interface{}
    json.NewDecoder(resp.Body).Decode(&result)
    data := result["data"].([]interface{})
    fmt.Printf("Found %d event types\n", len(data))
}
PHP
<?php

$url = 'https://api.hookmesh.com/v1/event-types?' . http_build_query([
    'limit' => 50,
    'search' => 'payment'
]);

$ch = curl_init($url);

curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('HOOKMESH_API_KEY')
    ]
]);

$response = curl_exec($ch);
$result = json_decode($response, true);

echo "Found " . count($result['data']) . " event types\n";

curl_close($ch);

Retrieve an Event Type

Get details for a specific event type by ID.

GET /v1/event-types/:id
Node.js
const eventTypeId = 'evt_2Zy3X8a9b0c1d2e3f4g5h6i7';

const response = await fetch(
  `https://api.hookmesh.com/v1/event-types/${eventTypeId}`,
  {
    headers: {
      'Authorization': `Bearer ${process.env.HOOKMESH_API_KEY}`
    }
  }
);

const eventType = await response.json();
console.log('Event type:', eventType.name);
console.log('Subscribers:', eventType.subscriber_count);
Python
event_type_id = 'evt_2Zy3X8a9b0c1d2e3f4g5h6i7'

response = requests.get(
    f'https://api.hookmesh.com/v1/event-types/{event_type_id}',
    headers={'Authorization': f'Bearer {os.environ["HOOKMESH_API_KEY"]}'}
)

event_type = response.json()
print(f'Event type: {event_type["name"]}')
print(f'Subscribers: {event_type["subscriber_count"]}')
Go
package main

import (
    "encoding/json"
    "fmt"
    "net/http"
    "os"
)

func main() {
    eventTypeID := "evt_2Zy3X8a9b0c1d2e3f4g5h6i7"

    req, _ := http.NewRequest("GET",
        "https://api.hookmesh.com/v1/event-types/"+eventTypeID,
        nil)

    req.Header.Set("Authorization", "Bearer "+os.Getenv("HOOKMESH_API_KEY"))

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()

    var eventType map[string]interface{}
    json.NewDecoder(resp.Body).Decode(&eventType)
    fmt.Printf("Event type: %s\n", eventType["name"])
    fmt.Printf("Subscribers: %.0f\n", eventType["subscriber_count"])
}
PHP
<?php

$eventTypeId = 'evt_2Zy3X8a9b0c1d2e3f4g5h6i7';

$ch = curl_init("https://api.hookmesh.com/v1/event-types/{$eventTypeId}");

curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('HOOKMESH_API_KEY')
    ]
]);

$response = curl_exec($ch);
$eventType = json_decode($response, true);

echo "Event type: {$eventType['name']}\n";
echo "Subscribers: {$eventType['subscriber_count']}\n";

curl_close($ch);

Update an Event Type

Update the description or schema for an event type. The name cannot be changed.

PATCH /v1/event-types/:id
âš 

Schema Changes

Changing the schema can break existing integrations. Use additive-only changes (add optional fields) or create a new versioned event type instead.

Node.js
const eventTypeId = 'evt_2Zy3X8a9b0c1d2e3f4g5h6i7';

const response = await fetch(
  `https://api.hookmesh.com/v1/event-types/${eventTypeId}`,
  {
    method: 'PATCH',
    headers: {
      'Authorization': `Bearer ${process.env.HOOKMESH_API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      description: 'Fired when a payment is successfully processed and settled',
      schema: {
        type: 'object',
        properties: {
          payment_id: { type: 'string' },
          amount: { type: 'number', minimum: 0 },
          currency: { type: 'string', pattern: '^[A-Z]{3}$' },
          customer_id: { type: 'string' },
          // New optional field (additive change - safe)
          settlement_date: { type: 'string', format: 'date-time' }
        },
        required: ['payment_id', 'amount', 'currency', 'customer_id']
      }
    })
  }
);

const updated = await response.json();
console.log('Event type updated:', updated.id);
Python
event_type_id = 'evt_2Zy3X8a9b0c1d2e3f4g5h6i7'

response = requests.patch(
    f'https://api.hookmesh.com/v1/event-types/{event_type_id}',
    headers={
        'Authorization': f'Bearer {os.environ["HOOKMESH_API_KEY"]}',
        'Content-Type': 'application/json'
    },
    json={
        'description': 'Fired when a payment is successfully processed and settled',
        'schema': {
            'type': 'object',
            'properties': {
                'payment_id': {'type': 'string'},
                'amount': {'type': 'number', 'minimum': 0},
                'currency': {'type': 'string', 'pattern': '^[A-Z]{3}$'},
                'customer_id': {'type': 'string'},
                # New optional field (additive change - safe)
                'settlement_date': {'type': 'string', 'format': 'date-time'}
            },
            'required': ['payment_id', 'amount', 'currency', 'customer_id']
        }
    }
)

updated = response.json()
print(f'Event type updated: {updated["id"]}')

Delete an Event Type

Permanently delete an event type. This operation fails if any endpoints are subscribed to this event type.

DELETE /v1/event-types/:id
âš 

Deletion Constraints

You cannot delete an event type if any endpoints are subscribed to it. Remove all subscriptions first, or use the force=true parameter to unsubscribe all endpoints automatically.

Node.js
const eventTypeId = 'evt_2Zy3X8a9b0c1d2e3f4g5h6i7';

// Check subscriber count first
const eventType = await fetch(
  `https://api.hookmesh.com/v1/event-types/${eventTypeId}`,
  {
    headers: { 'Authorization': `Bearer ${process.env.HOOKMESH_API_KEY}` }
  }
).then(r => r.json());

if (eventType.subscriber_count > 0) {
  console.warn(`${eventType.subscriber_count} endpoints subscribed - use force=true`);
}

// Delete with force to unsubscribe all endpoints
const response = await fetch(
  `https://api.hookmesh.com/v1/event-types/${eventTypeId}?force=true`,
  {
    method: 'DELETE',
    headers: {
      'Authorization': `Bearer ${process.env.HOOKMESH_API_KEY}`
    }
  }
);

console.log('Event type deleted');
Python
event_type_id = 'evt_2Zy3X8a9b0c1d2e3f4g5h6i7'

# Check subscriber count first
event_type = requests.get(
    f'https://api.hookmesh.com/v1/event-types/{event_type_id}',
    headers={'Authorization': f'Bearer {os.environ["HOOKMESH_API_KEY"]}'}
).json()

if event_type['subscriber_count'] > 0:
    print(f'{event_type["subscriber_count"]} endpoints subscribed - using force=true')

# Delete with force to unsubscribe all endpoints
response = requests.delete(
    f'https://api.hookmesh.com/v1/event-types/{event_type_id}',
    headers={'Authorization': f'Bearer {os.environ["HOOKMESH_API_KEY"]}'},
    params={'force': True}
)

print('Event type deleted')

Common Patterns

Schema Validation

Use JSON Schema to enforce payload structure and catch errors early.

Node.js - Strict Schema
await fetch('https://api.hookmesh.com/v1/event-types', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.HOOKMESH_API_KEY}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    name: 'order.shipped',
    description: 'Fired when an order is shipped to the customer',
    schema: {
      type: 'object',
      properties: {
        order_id: { type: 'string', pattern: '^ord_[a-zA-Z0-9]{20}$' },
        tracking_number: { type: 'string', minLength: 10 },
        carrier: { type: 'string', enum: ['USPS', 'FedEx', 'UPS', 'DHL'] },
        estimated_delivery: { type: 'string', format: 'date-time' },
        items: {
          type: 'array',
          items: {
            type: 'object',
            properties: {
              sku: { type: 'string' },
              quantity: { type: 'integer', minimum: 1 }
            },
            required: ['sku', 'quantity']
          },
          minItems: 1
        }
      },
      required: ['order_id', 'tracking_number', 'carrier', 'items'],
      additionalProperties: false // Reject unknown fields
    }
  })
});

Versioning Strategy

For breaking changes, create a new versioned event type instead of modifying the existing one.

Node.js - Version in Name
// Create v2 with breaking changes (new required field)
await fetch('https://api.hookmesh.com/v1/event-types', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.HOOKMESH_API_KEY}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    name: 'user.created.v2',
    description: 'Fired when a new user account is created (v2 with role)',
    schema: {
      type: 'object',
      properties: {
        user_id: { type: 'string' },
        email: { type: 'string', format: 'email' },
        role: { type: 'string', enum: ['admin', 'user', 'guest'] }, // New required field
        created_at: { type: 'string', format: 'date-time' }
      },
      required: ['user_id', 'email', 'role', 'created_at'] // role is now required
    }
  })
});

// Keep user.created.v1 for backward compatibility
// Migrate customers gradually to v2

Bulk Event Type Creation

Create multiple event types at once during initial setup.

Node.js - Bulk Setup
const eventTypes = [
  { name: 'user.created', description: 'New user account created' },
  { name: 'user.updated', description: 'User profile updated' },
  { name: 'user.deleted', description: 'User account deleted' },
  { name: 'payment.succeeded', description: 'Payment processed successfully' },
  { name: 'payment.failed', description: 'Payment processing failed' },
  { name: 'subscription.created', description: 'New subscription started' },
  { name: 'subscription.canceled', description: 'Subscription canceled' }
];

const results = await Promise.all(
  eventTypes.map(eventType =>
    fetch('https://api.hookmesh.com/v1/event-types', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${process.env.HOOKMESH_API_KEY}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(eventType)
    }).then(r => r.json())
  )
);

console.log(`Created ${results.length} event types`);

Best Practices

  • ✓
    Use lowercase.dot.notation - Keep event type names consistent and readable (order.shipped)
  • ✓
    Use past tense - Events describe completed actions (user.created not user.create)
  • ✓
    Define schemas early - Catch payload errors before they reach your customers
  • ✓
    Use additive-only changes - Only add optional fields to schemas, never remove or change existing fields
  • ✓
    Version for breaking changes - Create event.name.v2 instead of modifying existing schemas
  • ✓
    Check subscriber_count - Before making changes, know how many endpoints depend on this event type
  • ✓
    Document your events - Write clear descriptions so customers understand when events fire
  • ✓
    Group related events - Use consistent resource names (payment.succeeded, payment.failed, payment.refunded)

Related Documentation