Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.velahq.xyz/docs/llms.txt

Use this file to discover all available pages before exploring further.

VelaIngestClient sends events into your Vela app. It authenticates with your app’s API key (vela_live_...), which is scoped to a single app and can only ingest events — it cannot read or modify any data.

Constructor

import { VelaIngestClient } from '@vela-event/sdk';

const ingest = new VelaIngestClient(apiKey: string, options?: ClientOptions);
OptionTypeDefaultDescription
baseUrlstringhttps://api.velahq.xyzAPI base URL. Override for self-hosted instances.
timeoutnumber30000Request timeout in milliseconds.
fetchImpltypeof fetchglobalThis.fetchCustom fetch implementation (for Node 16 or testing).

Send a single event

const result = await ingest.ingest({
  event: 'order.placed',        // required — must match a registered schema's eventName
  data: {                        // required — validated against the schema's fields
    orderId: 'ord_abc123',
    amountCents: 4999,
    currency: 'USD',
  },
  level: 'info',                 // required — 'info' | 'warning' | 'error' | 'success'
  customer_id: 'cust_42',        // optional — link event to a customer for filtering
  metadata: {                    // optional — extra context (not validated against schema fields)
    environment: 'production',
    traceId: 'abc-def-123',
  },
  timestamp: '2024-06-01T12:00:00.000Z', // optional — defaults to server ingest time
});

console.log(result.accepted);      // 1
console.log(result.events[0].id);  // "evt_01j9abc..." — UUID of the stored event
console.log(result.events[0].eventName); // "order.placed"
console.log(result.events[0].createdAt); // ISO-8601 timestamp

Event fields reference

FieldRequiredTypeDescription
eventyesstringEvent name. Must match a registered schema’s eventName. Events without a matching schema are rejected with 400.
datayesobjectPayload object. Validated against the schema’s field definitions.
levelyesstringSeverity level — see table below.
customer_idnostringIdentifier for the customer this event is associated with. Enables per-customer filtering in the dashboard.
metadatanoobjectContextual data (environment, trace ID, etc.). Validated against schema metadataFields if defined.
timestampnostringISO-8601 timestamp for when the event occurred. Defaults to server ingest time if omitted.

Event levels

LevelWhen to useExamples
infoNormal business eventsorder.placed, user.signed_up, session.started
successCompleted flowspayment.captured, email.delivered, export.completed
warningDegraded but non-criticalretry.attempt, rate_limit_approaching, cache.miss
errorFailures requiring attentionpayment.failed, webhook.error, job.failed

Send a batch

Send up to 100 events in a single request. This is more efficient than sending events one by one when you have multiple events to ingest at the same time.
const result = await ingest.ingest([
  {
    event: 'order.placed',
    data: { orderId: 'ord_1', amountCents: 1999, currency: 'USD' },
    level: 'info',
    customer_id: 'cust_1',
  },
  {
    event: 'order.placed',
    data: { orderId: 'ord_2', amountCents: 8500, currency: 'EUR' },
    level: 'info',
    customer_id: 'cust_2',
  },
  {
    event: 'payment.failed',
    data: { orderId: 'ord_3', reason: 'card_declined', amountCents: 3000 },
    level: 'error',
  },
]);

console.log(result.accepted); // 3
console.log(result.events);   // array of 3 ingested event objects
Batch requests follow the same validation rules as single requests. If any event fails validation, only that event is rejected — the rest are accepted normally.

Response shape

Both single and batch ingestion return the same response type:
interface IngestResponse {
  accepted: number;     // Number of events successfully ingested
  events: {
    id: string;         // UUID of the stored event
    eventName: string;  // The event name
    createdAt: string;  // ISO-8601 timestamp of when it was stored
  }[];
}

Error handling

If validation fails, Vela returns a 400 error which the SDK throws as VelaValidationError:
import { VelaValidationError, VelaAuthError } from '@vela-event/sdk';

try {
  await ingest.ingest({
    event: 'order.placed',
    data: { orderId: 'ord_1' }, // missing required field amountCents
    level: 'info',
  });
} catch (err) {
  if (err instanceof VelaValidationError) {
    // Schema validation failed
    console.error(err.message);
    // "Event validation failed: field 'amountCents' is required"
  } else if (err instanceof VelaAuthError) {
    // Invalid or expired API key
    console.error('Check your VELA_API_KEY');
  }
}
See Error Handling for the full error hierarchy.

Ingesting from a queue consumer

A common pattern is to consume events from an internal queue and forward them to Vela:
import { VelaIngestClient } from '@vela-event/sdk';

const ingest = new VelaIngestClient(process.env.VELA_API_KEY!);

// In your queue consumer
async function processMessage(message: QueueMessage) {
  await ingest.ingest({
    event: message.type,
    data: message.payload,
    level: message.level ?? 'info',
    customer_id: message.customerId,
    timestamp: message.occurredAt,
  });
}