Skip to main content
Webhooks let your server receive real-time notifications when things happen on Hitorino — a stream goes live, a video is published, a viewer subscribes. Instead of polling the API repeatedly, you register a URL and Hitorino delivers a signed HTTP POST request to it whenever a matching event occurs. This page covers how to register, list, and remove webhook endpoints, as well as how to verify incoming payloads.

Webhook Events

Hitorino emits the following event types. You specify which events a webhook endpoint should receive when you register it.
EventTrigger
stream.startedA live stream transitions from scheduled or standby to live.
stream.endedA live stream ends and transitions to ended.
video.publishedA new on-demand video is made publicly available.
subscription.createdA viewer subscribes to a creator.
subscription.cancelledA viewer cancels their subscription to a creator.

Register a Webhook

Registers a new webhook endpoint. Hitorino immediately sends a POST request to your URL with a ping event to verify it’s reachable. Your endpoint must respond with 2xx within 5 seconds.
POST /webhooks
This endpoint requires a write-scoped API key.

Request Body

url
string
required
The HTTPS URL of your webhook endpoint. Must use https://. Hitorino does not support http:// endpoints.
events
array
required
Array of event type strings to subscribe to. Must contain at least one item. Use ["*"] to subscribe to all current and future events.

Request Examples

curl -X POST https://api.hitorino.tv/v1/webhooks \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://yourapp.com/webhooks/hitorino",
    "events": ["stream.started", "stream.ended", "video.published"]
  }'

Response

Returns 201 Created with the newly registered webhook object.
{
  "id": "wh_01HWBK1234",
  "url": "https://yourapp.com/webhooks/hitorino",
  "events": ["stream.started", "stream.ended", "video.published"],
  "secret": "whsec_a7b3c9d1e2f4g5h6i7j8k9l0m1n2o3p4q5r6s7t8",
  "status": "active",
  "created_at": "2024-06-15T10:00:00Z"
}
id
string
Unique identifier for the webhook registration, prefixed with wh_.
url
string
The HTTPS endpoint URL you registered.
events
array
Array of event type strings this webhook is subscribed to.
secret
string
A webhook signing secret used to verify incoming payloads. This value is returned only once, at creation time. Store it securely — you cannot retrieve it again. If you lose it, delete this webhook and create a new one.
status
string
Current status of the webhook registration. One of active or disabled. Hitorino may automatically disable a webhook after repeated delivery failures.
created_at
string
ISO 8601 timestamp of when the webhook was registered.
Copy the secret immediately. It is displayed exactly once in the registration response. Store it in your secrets manager alongside your API key.

List Webhooks

Returns all webhook endpoints registered to your account.
GET /webhooks

Request Examples

curl https://api.hitorino.tv/v1/webhooks \
  -H "Authorization: Bearer YOUR_API_KEY"

Response

{
  "data": [
    {
      "id": "wh_01HWBK1234",
      "url": "https://yourapp.com/webhooks/hitorino",
      "events": ["stream.started", "stream.ended", "video.published"],
      "status": "active",
      "created_at": "2024-06-15T10:00:00Z"
    }
  ]
}
The secret field is not returned on list responses. Only the registration response (POST /webhooks) includes the secret.

Delete a Webhook

Permanently removes a webhook registration. Hitorino immediately stops delivering events to the registered URL. This action cannot be undone.
DELETE /webhooks/{id}
This endpoint requires a write-scoped API key.

Path Parameters

id
string
required
The unique webhook ID to remove (e.g., wh_01HWBK1234).

Request Examples

curl -X DELETE https://api.hitorino.tv/v1/webhooks/wh_01HWBK1234 \
  -H "Authorization: Bearer YOUR_API_KEY"

Response

Returns 200 OK with a confirmation object.
{
  "deleted": true,
  "id": "wh_01HWBK1234"
}

Webhook Payload

When a subscribed event occurs, Hitorino sends a POST request to your endpoint with a JSON body structured as follows.
{
  "id": "evt_01HEVT9876",
  "type": "stream.started",
  "created_at": "2024-06-10T22:00:00Z",
  "data": {
    "id": "str_01HXYZ1234",
    "title": "Late Night Lo-Fi Coding",
    "status": "live",
    "creator_id": "usr_01HABC5678",
    "started_at": "2024-06-10T22:00:00Z",
    "stream_url": "https://watch.hitorino.tv/str_01HXYZ1234"
  }
}
id
string
Unique identifier for this event delivery, prefixed with evt_. Use this for idempotency checks in your handler.
type
string
The event type string that triggered this delivery (e.g., stream.started).
created_at
string
ISO 8601 timestamp of when the event was generated by Hitorino.
data
object
The event payload. The shape of this object varies by event type and mirrors the corresponding API resource object (stream, video, or subscription).

Signature Verification

Every webhook delivery includes an X-Hitorino-Signature header containing an HMAC-SHA256 signature of the raw request body, signed with your webhook secret. You should always verify this signature before processing the payload to ensure the request genuinely came from Hitorino.

How Signatures Work

  1. Hitorino computes HMAC-SHA256(rawBody, secret) and hex-encodes the result.
  2. The hex digest is sent in the X-Hitorino-Signature header.
  3. Your server recomputes the same HMAC using the raw request body and your stored secret, then compares it to the header value using a constant-time comparison.
Always verify the signature before deserializing or acting on the webhook payload. Skipping this step makes your endpoint vulnerable to forged events.

Verification Examples

const crypto = require('crypto');

function verifyWebhookSignature(rawBody, signature, secret) {
  const expectedSig = crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex');

  // Use timingSafeEqual to prevent timing attacks
  const sigBuffer = Buffer.from(signature, 'hex');
  const expectedBuffer = Buffer.from(expectedSig, 'hex');

  if (sigBuffer.length !== expectedBuffer.length) return false;
  return crypto.timingSafeEqual(sigBuffer, expectedBuffer);
}

// Express.js example
app.post('/webhooks/hitorino', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.headers['x-hitorino-signature'];
  const secret = process.env.HITORINO_WEBHOOK_SECRET;

  if (!verifyWebhookSignature(req.body, signature, secret)) {
    return res.status(401).json({ error: 'Invalid signature' });
  }

  const event = JSON.parse(req.body);
  console.log('Verified event:', event.type);

  res.status(200).json({ received: true });
});

Retry Behavior

If your endpoint responds with a non-2xx status code or times out (after 5 seconds), Hitorino retries the delivery with exponential backoff up to 5 attempts over approximately 24 hours. After all retries are exhausted, the event is marked as failed and no further attempts are made.
To handle retries safely, use the id field of the webhook payload as an idempotency key. Store processed event IDs in your database and skip any event whose id you’ve already handled.