API Documentation

Full reference: routes, authentication, CORS, examples and what to try on each endpoint.

Introduction

What problem Jobcelis solves, use cases, and API capabilities.

Every time you build an app that needs to notify other services, you end up writing the same logic: HTTP clients, retries, failure handling, delivery logs. In every project, reimplementing the same thing.

Jobcelis centralizes that infrastructure into one API. Send any JSON via HTTP POST — the platform routes, filters, transforms, and delivers to the configured destination URLs. No fixed schemas: topics, payloads, and rules are freely defined.

Usage examples

E-commerce

Order created → notify warehouse + billing + confirmation email

Payments

Payment completed → update order + send receipt + log in accounting

CI/CD

Successful deploy → monitoring + Slack + analytics tracker

SaaS

User registered → CRM + welcome email + analytics

Main capabilities

  • Events: JSON submission with optional topic via POST. No schema restrictions.
  • Webhooks: Destination URLs, filters (topic, amount, status), body_config (full, pick, rename, extra).
  • Deliveries: automatic retries with exponential backoff.
  • Jobs: daily, weekly, monthly or cron expression scheduling. Emits events or executes POST to destination URLs.
  • Topics: labels to filter and organize events.

Route groups

  • Public routes: register, login, refresh JWT. No API Key.
  • API Key routes: events, webhooks, deliveries, jobs, project. Token in Dashboard.

Responses in JSON. CORS enabled. Max payload 256 KB.

Core Concepts

Core platform concepts.

What is an event?

An event is a JSON message sent to Jobcelis via HTTP POST. Accepts any JSON structure: orders, payments, records, etc. Optionally includes a topic for classification. Jobcelis persists the event and, based on configured webhooks, delivers the information to specified destination URLs.

Example

{"topic": "order.created", "order_id": 123, "total": 99.99}

What is a webhook?

A webhook is a destination URL configured in the project. When an event matches the specified conditions (topic, filters), Jobcelis performs a POST to that URL with the configured payload.

What is a delivery?

Each event delivery attempt to a webhook URL generates a delivery record. The record has states: pending, success, or failed. On failure, Jobcelis automatically retries with exponential backoff.

What is a job?

A job is a scheduled task with daily, weekly, monthly, or cron expression scheduling. On execution, it emits an internal event or performs a POST to an external URL.

What is a topic?

A topic is an optional label for classifying events (e.g., order.created, payment.completed). Used as a filtering criterion in webhooks. Naming convention is freely defined by the user.

Quick Start

Initial setup steps for API integration.

1

Sign up and log in

Create an account on the platform with email and password. Access the Dashboard.

2

Obtain the API Token

The API token is located in the API Token section of the Dashboard. Store the complete token securely; it is required in all requests with header Authorization: Bearer YOUR_TOKEN or X-Api-Key: YOUR_TOKEN.

3

Send the first event

Send a POST request to /api/v1/events with a JSON body.

curl -X POST "https://jobcelis.com/api/v1/events" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"topic":"test","message":"Hello"}'
4

Configure a webhook

In the Dashboard, navigate to Webhooks > Create. Configure an accessible URL that accepts POST requests. Optionally, specify a topic to filter events.

5

Configure a job (optional)

In the Dashboard, navigate to Jobs > Create. Select schedule (daily, weekly, monthly, or cron) and action (emit event or POST to URL).

On error, verify that the API token is correctly included in the Authorization header and that the webhook URL is publicly accessible. Failed deliveries can be retried from the Dashboard.

Base URL

All examples use the current base URL:

https://jobcelis.com

In production, the base URL corresponds to the configured domain. The curl examples include this base.

Authentication

Authentication methods: API Key and JWT.

API Key routes:

Token authentication supports three methods:

  1. Header Authorization: Bearer <token>
  2. Header X-Api-Key: <token>
  3. Query param ?api_key=<token>

The API token is generated in the API Token section of the Dashboard. The complete value is displayed only at creation time. It must be stored securely.

Public routes (Auth)

Authentication endpoints do not require an API Key. Registration and login endpoints return a JWT for application authentication.

CORS

Cross-Origin Resource Sharing (CORS) configuration.

The API has CORS enabled for any origin (Access-Control-Allow-Origin: *). Any frontend (your SPA, another site, mobile WebView, etc.) can consume the API from its own URL without browser blocks.

Allowed headers:

  • Authorization
  • X-Api-Key
  • Content-Type, Accept

Methods: GET, POST, PUT, PATCH, DELETE, OPTIONS.

Auth (register/login)

Public routes without API Key. Body and response in JSON.

POST /api/v1/auth/register

Create a new account.

curl -X POST "https://jobcelis.com/api/v1/auth/register" \
  -H "Content-Type: application/json" \
  -d '{"name":"Test","email":"test@example.com","password":"SecurePass123!"}'
Response 201 Created
{
  "user": {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "email": "test@example.com",
    "name": "Test"
  },
  "token": "eyJhbGciOiJIUzI1NiIs...",
  "api_key": "jc_live_a1b2c3d4e5f6..."
}
POST /api/v1/auth/login

Log in and get JWT.

curl -X POST "https://jobcelis.com/api/v1/auth/login" \
  -H "Content-Type: application/json" \
  -d '{"email":"test@example.com","password":"SecurePass123!"}'
Response 200 OK

If MFA is enabled, mfa_required is returned instead of the token.

{
  "user": {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "email": "test@example.com",
    "name": "Test"
  },
  "token": "eyJhbGciOiJIUzI1NiIs..."
}

{
  "mfa_required": true,
  "mfa_token": "eyJhbGciOiJIUzI1NiIs..."
}
POST /api/v1/auth/refresh

Renew a JWT.

curl -X POST "https://jobcelis.com/api/v1/auth/refresh" \
  -H "Content-Type: application/json" \
  -d '{"token":"YOUR_JWT"}'
Response 200 OK
{
  "token": "eyJhbGciOiJIUzI1NiIs..."
}
POST /api/v1/auth/mfa/verify

Verify MFA code after login.

curl -X POST "https://jobcelis.com/api/v1/auth/mfa/verify" \
  -H "Content-Type: application/json" \
  -d '{"mfa_token":"TEMP_TOKEN","code":"123456"}'
Response 200 OK
{
  "user": {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "email": "test@example.com",
    "name": "Test"
  },
  "token": "eyJhbGciOiJIUzI1NiIs..."
}

Events

Event management: creation, listing, and retrieval.

POST /api/v1/events

Send a new event.

curl -X POST "https://jobcelis.com/api/v1/events" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"topic":"order.created","order_id":"12345","amount":99.99}'
Response 202 Accepted
{
  "event_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
  "payload_hash": "sha256:a3f2b8c1d4e5..."
}
POST /api/v1/send

Alias for POST /api/v1/events. Shortcut to send an event with the same body format and response.

curl -X POST "https://jobcelis.com/api/v1/send" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"topic":"order.created","order_id":"12345","amount":99.99}'
Response 202 Accepted
{
  "event_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
  "payload_hash": "sha256:a3f2b8c1d4e5..."
}
GET /api/v1/events

List events with pagination.

curl "https://jobcelis.com/api/v1/events?limit=10" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK
{
  "events": [
    {
      "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
      "topic": "order.created",
      "payload": {"order_id": "12345", "amount": 99.99},
      "status": "active",
      "occurred_at": "2026-01-15T10:30:00Z",
      "deliver_at": null,
      "payload_hash": "sha256:a3f2b8c1d4e5...",
      "idempotency_key": null,
      "inserted_at": "2026-01-15T10:30:00Z"
    }
  ],
  "has_next": true,
  "next_cursor": "c3d4e5f6-a7b8-9012-cdef-123456789012"
}
GET /api/v1/events/:id

Event detail

curl "https://jobcelis.com/api/v1/events/EVENT_ID" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK
{
  "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
  "topic": "order.created",
  "payload": {"order_id": "12345", "amount": 99.99},
  "status": "active",
  "occurred_at": "2026-01-15T10:30:00Z",
  "deliver_at": null,
  "payload_hash": "sha256:a3f2b8c1d4e5...",
  "idempotency_key": null,
  "inserted_at": "2026-01-15T10:30:00Z",
  "deliveries": [
    {"id": "d4e5f6a7-b8c9-0123-defg-234567890123", "status": "success", "attempt_number": 1}
  ]
}
DELETE /api/v1/events/:id

Delete an event.

curl -X DELETE "https://jobcelis.com/api/v1/events/EVENT_ID" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK
{
  "status": "inactive"
}

Webhooks

Create, list and manage webhooks.

GET /api/v1/webhooks

List project webhooks.

curl "https://jobcelis.com/api/v1/webhooks" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK
{
  "webhooks": [
    {
      "id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
      "url": "https://example.com/hook",
      "status": "active",
      "topics": ["order.*"],
      "filters": [],
      "body_config": {},
      "headers": {},
      "retry_config": {},
      "inserted_at": "2026-01-10T08:00:00Z"
    }
  ]
}
POST /api/v1/webhooks

Create a webhook

curl -X POST "https://jobcelis.com/api/v1/webhooks" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com/hook","topics":["order.*"]}'
Response 201 Created
{
  "id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
  "url": "https://example.com/hook",
  "status": "active",
  "topics": ["order.*"],
  "filters": [],
  "body_config": {},
  "headers": {},
  "retry_config": {},
  "inserted_at": "2026-01-10T08:00:00Z"
}
GET /api/v1/webhooks/:id

Webhook details.

curl "https://jobcelis.com/api/v1/webhooks/WEBHOOK_ID" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK
{
  "id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
  "url": "https://example.com/hook",
  "status": "active",
  "topics": ["order.*"],
  "filters": [],
  "body_config": {},
  "headers": {},
  "retry_config": {},
  "inserted_at": "2026-01-10T08:00:00Z"
}
PATCH /api/v1/webhooks/:id

Update a webhook.

curl -X PATCH "https://jobcelis.com/api/v1/webhooks/WEBHOOK_ID" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"active":false}'
Response 200 OK
{
  "id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
  "url": "https://example.com/hook",
  "status": "active",
  "topics": ["order.*"],
  "filters": [],
  "body_config": {},
  "headers": {},
  "retry_config": {},
  "inserted_at": "2026-01-10T08:00:00Z"
}
DELETE /api/v1/webhooks/:id

Delete a webhook.

curl -X DELETE "https://jobcelis.com/api/v1/webhooks/WEBHOOK_ID" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK
{
  "status": "inactive"
}
GET /api/v1/webhooks/:id/health

Retrieves the health status of a webhook.

curl "https://jobcelis.com/api/v1/webhooks/WEBHOOK_ID/health" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK
{
  "webhook_id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
  "url": "https://example.com/hook",
  "health": {
    "status": "healthy",
    "success_rate": 0.98,
    "avg_latency_ms": 120,
    "last_delivery_at": "2026-01-15T10:30:00Z"
  }
}

Deliveries

Delivery history and retries.

GET /api/v1/deliveries

List deliveries with optional filters.

curl "https://jobcelis.com/api/v1/deliveries?status=failed&limit=10" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK
{
  "deliveries": [
    {
      "id": "d4e5f6a7-b8c9-0123-defg-234567890123",
      "event_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
      "webhook_id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
      "status": "failed",
      "attempt_number": 3,
      "response_status": 500,
      "next_retry_at": "2026-01-15T11:00:00Z",
      "inserted_at": "2026-01-15T10:30:00Z"
    }
  ],
  "has_next": false,
  "next_cursor": null
}
POST /api/v1/deliveries/:id/retry

Retry a failed delivery.

curl -X POST "https://jobcelis.com/api/v1/deliveries/DELIVERY_ID/retry" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK
{
  "status": "retry_queued"
}

Jobs

Scheduled tasks: daily, weekly, monthly or cron.

GET /api/v1/jobs

List project jobs.

curl "https://jobcelis.com/api/v1/jobs" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK
{
  "jobs": [
    {
      "id": "e5f6a7b8-c9d0-1234-efgh-345678901234",
      "name": "Daily Report",
      "schedule_type": "daily",
      "schedule_config": {},
      "action_type": "emit_event",
      "action_config": {"topic": "report.daily", "payload": {}},
      "status": "active",
      "inserted_at": "2026-01-05T12:00:00Z"
    }
  ]
}
POST /api/v1/jobs

Create a scheduled job.

curl -X POST "https://jobcelis.com/api/v1/jobs" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"Daily Report","schedule_type":"daily","schedule_hour":0,"action_type":"emit_event","action_config":{"topic":"report.daily","payload":{}}}'
Response 201 Created
{
  "id": "e5f6a7b8-c9d0-1234-efgh-345678901234",
  "name": "Daily Report",
  "schedule_type": "daily",
  "schedule_config": {},
  "action_type": "emit_event",
  "action_config": {"topic": "report.daily", "payload": {}},
  "status": "active",
  "inserted_at": "2026-01-15T10:30:00Z"
}
GET /api/v1/jobs/:id

Event detail

curl "https://jobcelis.com/api/v1/jobs/JOB_ID" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK
{
  "id": "e5f6a7b8-c9d0-1234-efgh-345678901234",
  "name": "Daily Report",
  "schedule_type": "daily",
  "schedule_config": {},
  "action_type": "emit_event",
  "action_config": {"topic": "report.daily", "payload": {}},
  "status": "active",
  "inserted_at": "2026-01-05T12:00:00Z",
  "recent_runs": [
    {"id": "f6a7b8c9-d0e1-2345-fghi-456789012345", "executed_at": "2026-01-15T00:00:00Z", "status": "success", "result": null}
  ]
}
PATCH /api/v1/jobs/:id

Updating...

curl -X PATCH "https://jobcelis.com/api/v1/jobs/JOB_ID" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"Updated Report","schedule_hour":6}'
Response 200 OK
{
  "id": "e5f6a7b8-c9d0-1234-efgh-345678901234",
  "name": "Updated Report",
  "schedule_type": "daily",
  "schedule_config": {},
  "action_type": "emit_event",
  "action_config": {"topic": "report.daily", "payload": {}},
  "status": "active",
  "inserted_at": "2026-01-05T12:00:00Z"
}
DELETE /api/v1/jobs/:id

Deleting...

curl -X DELETE "https://jobcelis.com/api/v1/jobs/JOB_ID" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK
{
  "status": "inactive"
}
GET /api/v1/jobs/:id/runs

Job execution history.

curl "https://jobcelis.com/api/v1/jobs/JOB_ID/runs" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK
{
  "runs": [
    {
      "id": "f6a7b8c9-d0e1-2345-fghi-456789012345",
      "executed_at": "2026-01-15T00:00:00Z",
      "status": "success",
      "result": null
    }
  ]
}
GET /api/v1/jobs/cron-preview

Preview the next executions of a cron expression.

curl "https://jobcelis.com/api/v1/jobs/cron-preview?expression=*/15+*+*+*+*" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK
{
  "expression": "*/15 * * * *",
  "next_executions": [
    "2026-01-15T10:45:00Z",
    "2026-01-15T11:00:00Z",
    "2026-01-15T11:15:00Z",
    "2026-01-15T11:30:00Z",
    "2026-01-15T11:45:00Z"
  ]
}

Project & API Token

View and update your project, manage API tokens.

GET /api/v1/project

Current project details.

curl "https://jobcelis.com/api/v1/project" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK
{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "name": "My Project",
  "status": "active",
  "settings": {}
}
PATCH /api/v1/project

Update the project name.

curl -X PATCH "https://jobcelis.com/api/v1/project" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"My Project"}'
Response 200 OK
{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "name": "My Project",
  "status": "active"
}
GET /api/v1/topics

List all used topics.

curl "https://jobcelis.com/api/v1/topics" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK
{
  "topics": ["order.created", "order.updated", "payment.completed", "user.registered"]
}
GET /api/v1/token

Show current token info (prefix).

curl "https://jobcelis.com/api/v1/token" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK
{
  "prefix": "jc_live_a1b2",
  "message": "Use Authorization: Bearer <your_key>. Regenerate from dashboard to get a new key."
}
POST /api/v1/token/regenerate

Regenerate the API token. The previous one stops working.

curl -X POST "https://jobcelis.com/api/v1/token/regenerate" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK
{
  "token": "jc_live_new_token_value_here...",
  "message": "The previous token no longer works. Only this token is valid. Save it; it is only shown once."
}
When regenerating, the previous token is invalidated immediately. Update your code with the new token.

Pipelines

Event processing pipelines with sequential transformation steps.

GET /api/v1/pipelines

Lists project pipelines.

curl "https://jobcelis.com/api/v1/pipelines" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK
{
  "data": [
    {
      "id": "f6a7b8c9-d0e1-2345-fghi-456789012345",
      "name": "Order Pipeline",
      "status": "active",
      "description": "Process orders",
      "topics": ["order.*"],
      "steps": [{"type": "filter", "config": {"field": "amount", "operator": "gt", "value": 100}}],
      "webhook_id": null,
      "inserted_at": "2026-01-10T08:00:00Z"
    }
  ]
}
POST /api/v1/pipelines

Creates a new processing pipeline.

curl -X POST "https://jobcelis.com/api/v1/pipelines" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"Order Pipeline","description":"Process orders","steps":[{"type":"filter","config":{"field":"amount","operator":"gt","value":100}}]}'
Response 201 Created
{
  "data": {
    "id": "f6a7b8c9-d0e1-2345-fghi-456789012345",
    "name": "Order Pipeline",
    "status": "active",
    "description": "Process orders",
    "topics": null,
    "steps": [{"type": "filter", "config": {"field": "amount", "operator": "gt", "value": 100}}],
    "webhook_id": null,
    "inserted_at": "2026-01-15T10:30:00Z"
  }
}
GET /api/v1/pipelines/:id

Retrieves detailed pipeline configuration.

curl "https://jobcelis.com/api/v1/pipelines/PIPELINE_ID" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK
{
  "data": {
    "id": "f6a7b8c9-d0e1-2345-fghi-456789012345",
    "name": "Order Pipeline",
    "status": "active",
    "description": "Process orders",
    "topics": ["order.*"],
    "steps": [{"type": "filter", "config": {"field": "amount", "operator": "gt", "value": 100}}],
    "webhook_id": null,
    "inserted_at": "2026-01-10T08:00:00Z"
  }
}
PATCH /api/v1/pipelines/:id

Updates pipeline configuration.

curl -X PATCH "https://jobcelis.com/api/v1/pipelines/PIPELINE_ID" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"Updated Pipeline","description":"New description"}'
Response 200 OK
{
  "data": {
    "id": "f6a7b8c9-d0e1-2345-fghi-456789012345",
    "name": "Updated Pipeline",
    "status": "active",
    "description": "New description",
    "topics": ["order.*"],
    "steps": [{"type": "filter", "config": {"field": "amount", "operator": "gt", "value": 100}}],
    "webhook_id": null,
    "inserted_at": "2026-01-10T08:00:00Z"
  }
}
DELETE /api/v1/pipelines/:id

Deletes a pipeline and its associated configurations.

curl -X DELETE "https://jobcelis.com/api/v1/pipelines/PIPELINE_ID" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 204 No Content
No content.
POST /api/v1/pipelines/:id/test

Executes a pipeline with test payload without persisting results.

curl -X POST "https://jobcelis.com/api/v1/pipelines/PIPELINE_ID/test" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"topic":"order.created","payload":{"order_id":"123","amount":99.99}}'
Response 200 OK
{
  "input": {"order_id": "123", "amount": 99.99},
  "output": {"order_id": "123", "amount": 99.99},
  "steps_count": 1,
  "status": "passed"
}

Dead Letters

Events that exhausted all configured delivery attempts.

GET /api/v1/dead-letters

Lists undelivered events (dead letters) for the project.

curl "https://jobcelis.com/api/v1/dead-letters" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK
{
  "dead_letters": [
    {
      "id": "a7b8c9d0-e1f2-3456-ghij-567890123456",
      "project_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "delivery_id": "d4e5f6a7-b8c9-0123-defg-234567890123",
      "event_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
      "webhook_id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
      "webhook_url": "https://example.com/hook",
      "original_payload": {"order_id": "12345"},
      "last_error": "Connection refused",
      "last_response_status": null,
      "attempts_exhausted": 5,
      "resolved": false,
      "resolved_at": null,
      "inserted_at": "2026-01-15T10:30:00Z"
    }
  ]
}
GET /api/v1/dead-letters/:id

Retrieves full details of a dead letter.

curl "https://jobcelis.com/api/v1/dead-letters/DEAD_LETTER_ID" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK
{
  "id": "a7b8c9d0-e1f2-3456-ghij-567890123456",
  "project_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "delivery_id": "d4e5f6a7-b8c9-0123-defg-234567890123",
  "event_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
  "webhook_id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
  "webhook_url": "https://example.com/hook",
  "original_payload": {"order_id": "12345"},
  "last_error": "Connection refused",
  "last_response_status": null,
  "attempts_exhausted": 5,
  "resolved": false,
  "resolved_at": null,
  "inserted_at": "2026-01-15T10:30:00Z"
}
POST /api/v1/dead-letters/:id/retry

Retries delivery of a dead letter to the webhook endpoint.

curl -X POST "https://jobcelis.com/api/v1/dead-letters/DEAD_LETTER_ID/retry" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK
{
  "status": "retrying",
  "delivery_id": "d4e5f6a7-b8c9-0123-defg-234567890123"
}
PATCH /api/v1/dead-letters/:id/resolve

Marks a dead letter as resolved, removing it from the queue.

curl -X PATCH "https://jobcelis.com/api/v1/dead-letters/DEAD_LETTER_ID/resolve" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK
{
  "status": "resolved"
}

Event Replay

Re-delivers historical events to webhook endpoints.

POST /api/v1/replays

Creates a replay job to re-deliver events within a time range.

curl -X POST "https://jobcelis.com/api/v1/replays" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"webhook_id":"WEBHOOK_ID","from":"2026-01-01T00:00:00Z","to":"2026-01-31T23:59:59Z"}'
Response 201 Created
{
  "id": "b8c9d0e1-f2a3-4567-hijk-678901234567",
  "status": "pending",
  "filters": {"webhook_id": "WEBHOOK_ID", "from_date": "2026-01-01T00:00:00Z", "to_date": "2026-01-31T23:59:59Z"},
  "total_events": 0,
  "processed_events": 0,
  "started_at": null,
  "completed_at": null,
  "inserted_at": "2026-01-15T10:30:00Z"
}
GET /api/v1/replays

Lists replay jobs with their status and progress.

curl "https://jobcelis.com/api/v1/replays" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK
{
  "data": [
    {
      "id": "b8c9d0e1-f2a3-4567-hijk-678901234567",
      "status": "completed",
      "filters": {"webhook_id": "WEBHOOK_ID", "from_date": "2026-01-01T00:00:00Z"},
      "total_events": 42,
      "processed_events": 42,
      "started_at": "2026-01-15T10:31:00Z",
      "completed_at": "2026-01-15T10:32:00Z",
      "inserted_at": "2026-01-15T10:30:00Z"
    }
  ]
}
GET /api/v1/replays/:id

Retrieves the status and configuration of a specific replay.

curl "https://jobcelis.com/api/v1/replays/REPLAY_ID" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK
{
  "id": "b8c9d0e1-f2a3-4567-hijk-678901234567",
  "status": "running",
  "filters": {"webhook_id": "WEBHOOK_ID"},
  "total_events": 42,
  "processed_events": 15,
  "started_at": "2026-01-15T10:31:00Z",
  "completed_at": null,
  "inserted_at": "2026-01-15T10:30:00Z"
}
DELETE /api/v1/replays/:id

Cancels an in-progress replay, stopping pending deliveries.

curl -X DELETE "https://jobcelis.com/api/v1/replays/REPLAY_ID" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK
{
  "id": "b8c9d0e1-f2a3-4567-hijk-678901234567",
  "status": "cancelled",
  "filters": {"webhook_id": "WEBHOOK_ID"},
  "total_events": 42,
  "processed_events": 15,
  "started_at": "2026-01-15T10:31:00Z",
  "completed_at": "2026-01-15T10:35:00Z",
  "inserted_at": "2026-01-15T10:30:00Z"
}

Event Schemas

Event structure definition and validation using JSON Schema.

GET /api/v1/event-schemas

Lists JSON schemas registered for event validation.

curl "https://jobcelis.com/api/v1/event-schemas" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK
{
  "data": [
    {
      "id": "c9d0e1f2-a3b4-5678-ijkl-789012345678",
      "project_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "topic": "order.created",
      "schema": {"type": "object", "required": ["order_id"], "properties": {"order_id": {"type": "string"}}},
      "version": 1,
      "status": "active",
      "inserted_at": "2026-01-10T08:00:00Z",
      "updated_at": "2026-01-10T08:00:00Z"
    }
  ]
}
POST /api/v1/event-schemas

Creates a new JSON Schema for payload validation.

curl -X POST "https://jobcelis.com/api/v1/event-schemas" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"topic":"order.created","schema":{"type":"object","required":["order_id"],"properties":{"order_id":{"type":"string"}}}}'
Response 201 Created
{
  "data": {
    "id": "c9d0e1f2-a3b4-5678-ijkl-789012345678",
    "project_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "topic": "order.created",
    "schema": {"type": "object", "required": ["order_id"], "properties": {"order_id": {"type": "string"}}},
    "version": 1,
    "status": "active",
    "inserted_at": "2026-01-15T10:30:00Z",
    "updated_at": "2026-01-15T10:30:00Z"
  }
}
GET /api/v1/event-schemas/:id

Retrieves the complete JSON Schema definition.

curl "https://jobcelis.com/api/v1/event-schemas/SCHEMA_ID" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK
{
  "data": {
    "id": "c9d0e1f2-a3b4-5678-ijkl-789012345678",
    "project_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "topic": "order.created",
    "schema": {"type": "object", "required": ["order_id"], "properties": {"order_id": {"type": "string"}}},
    "version": 1,
    "status": "active",
    "inserted_at": "2026-01-10T08:00:00Z",
    "updated_at": "2026-01-10T08:00:00Z"
  }
}
PATCH /api/v1/event-schemas/:id

Updates a JSON Schema and increments the version number.

curl -X PATCH "https://jobcelis.com/api/v1/event-schemas/SCHEMA_ID" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"schema":{"type":"object","required":["order_id","amount"],"properties":{"order_id":{"type":"string"},"amount":{"type":"number"}}}}'
Response 200 OK
{
  "data": {
    "id": "c9d0e1f2-a3b4-5678-ijkl-789012345678",
    "project_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "topic": "order.created",
    "schema": {"type": "object", "required": ["order_id", "amount"], "properties": {"order_id": {"type": "string"}, "amount": {"type": "number"}}},
    "version": 1,
    "status": "active",
    "inserted_at": "2026-01-10T08:00:00Z",
    "updated_at": "2026-01-15T10:30:00Z"
  }
}
DELETE /api/v1/event-schemas/:id

Deletes a JSON Schema from the project.

curl -X DELETE "https://jobcelis.com/api/v1/event-schemas/SCHEMA_ID" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK
{
  "ok": true
}
POST /api/v1/event-schemas/validate

Validates a payload against a JSON Schema without persisting the event.

curl -X POST "https://jobcelis.com/api/v1/event-schemas/validate" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"topic":"order.created","payload":{"order_id":"123"}}'
Response 200 OK
{
  "valid": true,
  "errors": []
}

// If validation fails:
{
  "valid": false,
  "errors": [
    {"message": "Required property order_id is missing", "path": "#/order_id"}
  ]
}

Data Export

Project data export in CSV or JSON format.

GET /api/v1/export/events

Exports events with full metadata and payload.

curl "https://jobcelis.com/api/v1/export/events?format=csv" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK

CSV format by default. Use ?format=json for JSON output.

id,topic,status,occurred_at,payload,payload_hash
b2c3d4e5-...,order.created,active,2026-01-15T10:30:00Z,"{""order_id"":""12345""}",sha256:a3f2...
GET /api/v1/export/deliveries

Exports delivery records with attempt history.

curl "https://jobcelis.com/api/v1/export/deliveries?format=csv" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK

CSV format by default. Use ?format=json for JSON output.

id,event_id,webhook_id,status,attempt_number,response_status,inserted_at
d4e5f6a7-...,b2c3d4e5-...,c3d4e5f6-...,success,1,200,2026-01-15T10:30:00Z
GET /api/v1/export/jobs

Exports scheduled jobs with status and configuration.

curl "https://jobcelis.com/api/v1/export/jobs?format=csv" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK

CSV format by default. Use ?format=json for JSON output.

id,name,status,schedule_type,action_type,inserted_at
e5f6a7b8-...,Daily Report,active,daily,emit_event,2026-01-05T12:00:00Z
GET /api/v1/export/audit-log

Exports the complete audit log with action metadata.

curl "https://jobcelis.com/api/v1/export/audit-log?format=csv" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK

CSV format by default. Use ?format=json for JSON output.

id,action,resource_type,resource_id,user_id,ip_address,inserted_at
f6a7b8c9-...,event.created,event,b2c3d4e5-...,a1b2c3d4-...,192.168.1.1,2026-01-15T10:30:00Z
Use the query parameter ?format=csv for CSV or ?format=json for JSON. Default format is CSV.

Dashboard

Main control panel for project resource management.

The Dashboard is the primary management interface. Enables viewing events, webhooks, deliveries, jobs, analytics, audit log, and API token management. Accessed via the web application after authentication.

Main sections

  • Events: list, detail, filters
  • Webhooks: create, edit, enable/disable
  • Deliveries: history, retries
  • Jobs: create, edit, view executions

Tools

  • Analytics: charts and metrics
  • Audit Log: action records
  • Sandbox: test endpoints
  • API Token: view and regenerate

Account Settings

Profile, credentials, and multi-factor authentication management.

From the account page, name, email, and password can be updated. Two-factor authentication (MFA) can also be enabled for additional security.

Password Recovery

Credential recovery process.

If the password is lost, request a recovery link from the login page. An email with a temporary link will be sent to set a new password.

Recovery links have limited validity for security. If expired, request a new one.

Multi-project

Multi-project management from a single account.

Multiple isolated projects can be created, each with its own API token, webhooks, events, and configuration. Enables separation of environments (dev, staging, prod) or different applications.

GET /api/v1/projects

Lists projects associated with the authenticated account (requires JWT).

curl "https://jobcelis.com/api/v1/projects" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK
{
  "data": [
    {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "name": "Production",
      "status": "active",
      "is_default": true,
      "settings": {},
      "inserted_at": "2026-01-01T00:00:00Z",
      "updated_at": "2026-01-10T08:00:00Z"
    }
  ]
}
POST /api/v1/projects

Creates a new project with default settings and generates an API token.

curl -X POST "https://jobcelis.com/api/v1/projects" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"My New Project"}'
Response 201 Created
{
  "data": {
    "id": "d0e1f2a3-b4c5-6789-klmn-890123456789",
    "name": "My New Project",
    "status": "active",
    "is_default": false,
    "settings": {},
    "inserted_at": "2026-01-15T10:30:00Z",
    "updated_at": "2026-01-15T10:30:00Z"
  }
}
PATCH /api/v1/projects/:id/default

Sets a project as the default for API requests.

curl -X PATCH "https://jobcelis.com/api/v1/projects/PROJECT_ID/default" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK
{
  "data": {
    "id": "d0e1f2a3-b4c5-6789-klmn-890123456789",
    "name": "My New Project",
    "status": "active",
    "is_default": true,
    "settings": {},
    "inserted_at": "2026-01-15T10:30:00Z",
    "updated_at": "2026-01-15T10:35:00Z"
  }
}
GET /api/v1/projects/:id

Retrieves the details of a specific project by its ID (requires JWT).

curl "https://jobcelis.com/api/v1/projects/PROJECT_ID" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
Response 200 OK
{
  "data": {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "name": "Production",
    "status": "active",
    "is_default": true,
    "settings": {},
    "inserted_at": "2026-01-01T00:00:00Z",
    "updated_at": "2026-01-10T08:00:00Z"
  }
}
PATCH /api/v1/projects/:id

Updates the name, settings, or retention policy of an existing project.

curl -X PATCH "https://jobcelis.com/api/v1/projects/PROJECT_ID" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"Updated Project Name","settings":{"notifications":true}}'
Response 200 OK
{
  "data": {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "name": "Updated Project Name",
    "status": "active",
    "is_default": true,
    "settings": {"notifications": true},
    "inserted_at": "2026-01-01T00:00:00Z",
    "updated_at": "2026-01-15T12:00:00Z"
  }
}
DELETE /api/v1/projects/:id

Deletes a project (only the owner can do this). Associated data is deactivated.

curl -X DELETE "https://jobcelis.com/api/v1/projects/PROJECT_ID" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
Response 200 OK
{
  "ok": true
}

Teams

Team management and permissions in shared projects.

Allows inviting members to projects with differentiated roles (admin, member, viewer). Invited members receive an email notification and must accept the invitation to gain access.

GET /api/v1/projects/:id/members

Lists project members with their assigned roles.

curl "https://jobcelis.com/api/v1/projects/PROJECT_ID/members" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK
{
  "data": [
    {
      "id": "e1f2a3b4-c5d6-7890-lmno-901234567890",
      "project_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "user_id": "f2a3b4c5-d6e7-8901-mnop-012345678901",
      "role": "member",
      "status": "accepted",
      "invited_by": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "inserted_at": "2026-01-10T08:00:00Z"
    }
  ]
}
POST /api/v1/projects/:id/members

Sends an invitation to add a member to the project.

curl -X POST "https://jobcelis.com/api/v1/projects/PROJECT_ID/members" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"email":"member@example.com","role":"member"}'
Response 201 Created
{
  "data": {
    "id": "e1f2a3b4-c5d6-7890-lmno-901234567890",
    "project_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "user_id": "f2a3b4c5-d6e7-8901-mnop-012345678901",
    "role": "member",
    "status": "pending",
    "invited_by": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "inserted_at": "2026-01-15T10:30:00Z"
  }
}
PATCH /api/v1/projects/:id/members/:mid

Modifies the role assigned to a project member.

curl -X PATCH "https://jobcelis.com/api/v1/projects/PROJECT_ID/members/MEMBER_ID" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"role":"admin"}'
Response 200 OK
{
  "data": {
    "id": "e1f2a3b4-c5d6-7890-lmno-901234567890",
    "project_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "user_id": "f2a3b4c5-d6e7-8901-mnop-012345678901",
    "role": "admin",
    "status": "accepted",
    "invited_by": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "inserted_at": "2026-01-10T08:00:00Z"
  }
}
DELETE /api/v1/projects/:id/members/:mid

Removes a member from the project, revoking all access permissions.

curl -X DELETE "https://jobcelis.com/api/v1/projects/PROJECT_ID/members/MEMBER_ID" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK
{
  "ok": true
}
GET /api/v1/invitations/pending

Lists the pending invitations for the authenticated user across all projects.

curl "https://jobcelis.com/api/v1/invitations/pending" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
Response 200 OK
{
  "data": [
    {
      "id": "f3a4b5c6-d7e8-9012-opqr-345678901234",
      "project_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "user_id": "f2a3b4c5-d6e7-8901-mnop-012345678901",
      "role": "member",
      "status": "pending",
      "invited_by": "c3d4e5f6-a7b8-9012-cdef-234567890abc",
      "inserted_at": "2026-01-20T09:00:00Z"
    }
  ]
}
POST /api/v1/invitations/:id/accept

Accepts a pending invitation, granting access to the project with the assigned role.

curl -X POST "https://jobcelis.com/api/v1/invitations/INVITATION_ID/accept" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
Response 200 OK
{
  "data": {
    "id": "f3a4b5c6-d7e8-9012-opqr-345678901234",
    "project_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "user_id": "f2a3b4c5-d6e7-8901-mnop-012345678901",
    "role": "member",
    "status": "accepted",
    "invited_by": "c3d4e5f6-a7b8-9012-cdef-234567890abc",
    "inserted_at": "2026-01-20T09:00:00Z"
  }
}
POST /api/v1/invitations/:id/reject

Rejects a pending invitation, declining access to the project.

curl -X POST "https://jobcelis.com/api/v1/invitations/INVITATION_ID/reject" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
Response 200 OK
{
  "data": {
    "id": "f3a4b5c6-d7e8-9012-opqr-345678901234",
    "project_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "user_id": "f2a3b4c5-d6e7-8901-mnop-012345678901",
    "role": "member",
    "status": "rejected",
    "invited_by": "c3d4e5f6-a7b8-9012-cdef-234567890abc",
    "inserted_at": "2026-01-20T09:00:00Z"
  }
}

Sandbox

Testing endpoints for webhook verification and integration.

Create isolated sandbox endpoints to test webhook integrations without requiring external infrastructure. Each endpoint provides a unique URL that captures and logs all incoming HTTP requests.

GET /api/v1/sandbox-endpoints

Lists sandbox endpoints created for webhook testing.

curl "https://jobcelis.com/api/v1/sandbox-endpoints" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK
{
  "data": [
    {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "slug": "test-endpoint-x7k9",
      "name": "Test Endpoint",
      "url": "/sandbox/test-endpoint-x7k9",
      "expires_at": "2026-03-14T14:30:00Z",
      "inserted_at": "2026-03-07T14:30:00Z"
    }
  ]
}
POST /api/v1/sandbox-endpoints

Creates a new sandbox endpoint for testing and request inspection.

curl -X POST "https://jobcelis.com/api/v1/sandbox-endpoints" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"Test Endpoint"}'
Response 201 Created
{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "slug": "test-endpoint-x7k9",
  "name": "Test Endpoint",
  "url": "/sandbox/test-endpoint-x7k9",
  "expires_at": "2026-03-14T14:30:00Z",
  "inserted_at": "2026-03-07T14:30:00Z"
}
GET /api/v1/sandbox-endpoints/:id/requests

Retrieves all HTTP requests received by a sandbox endpoint.

curl "https://jobcelis.com/api/v1/sandbox-endpoints/ENDPOINT_ID/requests" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK
{
  "data": [
    {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "method": "POST",
      "path": "/sandbox/test-endpoint-x7k9",
      "headers": {"content-type": "application/json"},
      "body": {"order_id": "123", "amount": 99.99},
      "query_params": {},
      "ip": "203.0.113.42",
      "inserted_at": "2026-03-07T14:30:00Z"
    }
  ]
}
DELETE /api/v1/sandbox-endpoints/:id

Deletes a sandbox endpoint and discards all captured data.

curl -X DELETE "https://jobcelis.com/api/v1/sandbox-endpoints/ENDPOINT_ID" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK
{
  "status": "deleted"
}

Analytics

Project performance metrics and visualizations.

GET /api/v1/analytics/events-per-day

Daily event volume.

curl "https://jobcelis.com/api/v1/analytics/events-per-day" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK
{
  "data": [
    {"date": "2026-03-05", "count": 245},
    {"date": "2026-03-06", "count": 312},
    {"date": "2026-03-07", "count": 178}
  ]
}
GET /api/v1/analytics/deliveries-per-day

Daily delivery volume.

curl "https://jobcelis.com/api/v1/analytics/deliveries-per-day" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK
{
  "data": [
    {"date": "2026-03-05", "count": 320},
    {"date": "2026-03-06", "count": 415},
    {"date": "2026-03-07", "count": 198}
  ]
}
GET /api/v1/analytics/top-topics

Top event topics by volume.

curl "https://jobcelis.com/api/v1/analytics/top-topics" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK
{
  "data": [
    {"topic": "order.created", "count": 1250},
    {"topic": "user.signup", "count": 890},
    {"topic": "payment.completed", "count": 567}
  ]
}
GET /api/v1/analytics/webhook-stats

Webhook performance statistics.

curl "https://jobcelis.com/api/v1/analytics/webhook-stats" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK
{
  "data": [
    {
      "webhook_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "url": "https://example.com/hook",
      "total_deliveries": 150,
      "successful": 142,
      "failed": 8
    }
  ]
}

Audit Log

Immutable action log for the project.

GET /api/v1/audit-log

Retrieves audit log entries with pagination support.

curl "https://jobcelis.com/api/v1/audit-log?limit=20" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK
{
  "data": [
    {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "action": "webhook.created",
      "resource_type": "webhook",
      "resource_id": "f1e2d3c4-b5a6-7890-fedc-ba0987654321",
      "metadata": {"url": "https://example.com/hook"},
      "user_id": "c3d4e5f6-a7b8-9012-cdef-234567890abc",
      "ip_address": "203.0.113.42",
      "inserted_at": "2026-03-07T14:30:00Z"
    }
  ]
}

Optional filters: action, actor_email, from, to.

Real-time Streaming

Receive events and delivery updates in real time via SSE (Server-Sent Events) or WebSocket (Phoenix Channel). Two protocols, same data.

Message types

Both protocols (SSE and WebSocket) transmit the same message types:

Message When it fires Fields
event.created Every time a new event arrives at the project id, topic, payload, occurred_at
delivery.updated Every time a webhook responds (success or failure) id, status, event_id
connected When the connection is established (SSE only) project_id
keepalive Every 30 seconds to keep the connection alive (SSE only)

SSE vs WebSocket

SSE WebSocket
Endpoint GET /api/v1/stream WS /ws
Authentication Header Authorization / X-Api-Key Query param ?token=API_KEY
Address Unidirectional (server → client) Bidirectional
Reconnection Automatic in browsers (EventSource) Automatic with Phoenix Socket
Ideal for curl, scripts, CLIs, simple integrations Frontend apps, dashboards, persistent services
Scope events:read events:read
Timeout 120 seconds of inactivity (reconnect) 120 seconds of inactivity (reconnect)

SSE (Server-Sent Events)

GET /api/v1/stream

Establishes an SSE connection to receive events and delivery updates in real time. The connection stays open and transmits data as it occurs.

curl -N "https://jobcelis.com/api/v1/stream" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK

Server-Sent Events stream.

data: {"type":"connected","project_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"}

data: {"type":"event.created","data":{"id":"b2c3d4e5-f6a7-8901-bcde-f12345678901","topic":"order.created","payload":{"order_id":"123"},"occurred_at":"2026-03-07T14:30:00Z"}}

data: {"type":"delivery.updated","data":{"id":"c3d4e5f6-a7b8-9012-cdef-234567890abc","status":"delivered","event_id":"b2c3d4e5-f6a7-8901-bcde-f12345678901"}}

: keepalive

JavaScript (browser or Node.js)

const source = new EventSource(
  "https://jobcelis.com/api/v1/stream",
  { headers: { "Authorization": "Bearer YOUR_TOKEN" } }
);

source.onmessage = (event) => {
  const data = JSON.parse(event.data);

  if (data.type === "event.created") {
    console.log("New event:", data.data.topic, data.data.payload);
  }

  if (data.type === "delivery.updated") {
    console.log("Delivery:", data.data.id, "→", data.data.status);
  }
};

source.onerror = () => console.log("Reconnecting...");

Python

import requests, json

response = requests.get(
    "https://jobcelis.com/api/v1/stream",
    headers={"Authorization": "Bearer YOUR_TOKEN"},
    stream=True
)

for line in response.iter_lines():
    if line and line.startswith(b"data: "):
        event = json.loads(line[6:])
        print(f"{event['type']}: {event.get('data', {})}")

WebSocket (Phoenix Channel)

Persistent connection via WebSocket using Phoenix Channel. Authentication with API Key as query param. The channel is events:<project_id>.

Endpoint

WS wss://jobcelis.com/ws?token=YOUR_TOKEN

Channel

events:YOUR_PROJECT_ID

JavaScript with Phoenix Socket

import { Socket } from "phoenix";

const socket = new Socket("wss://jobcelis.com/ws", {
  params: { token: "YOUR_TOKEN" }
});
socket.connect();

const channel = socket.channel("events:YOUR_PROJECT_ID", {});

channel.join()
  .receive("ok", () => console.log("Connected to stream"))
  .receive("error", (resp) => console.log("Error:", resp));

// Listen for new events
channel.on("event:created", (event) => {
  console.log("New event:", event.topic, event.payload);
});

// Listen for delivery updates
channel.on("delivery:updated", (delivery) => {
  console.log("Delivery", delivery.id, "→", delivery.status);
});

Install phoenix with: npm install phoenix. The package provides the Socket client with automatic reconnection.

Use cases

Terminal monitor

Run curl -N in a terminal to watch events flowing in real time while developing. Ideal for debugging.

Microservice without webhook

A service connects to the stream and processes events without needing to expose a public URL. No firewall, no DNS.

Real-time dashboard

Show live activity in your own interface. Events appear instantly without reloading the page.

Instant alerts

React instantly when a delivery fails. Listen to delivery.updated and filter by status to send alerts to Slack, email or another channel.

Topic Wildcards

Wildcard patterns with * for filtering multiple webhook topics.

Webhook topics support pattern matching with wildcards. The pattern order.* matches order.created, order.updated, order.deleted, and similar topics under that namespace.

Pattern Matches
order.* order.created, order.updated
*.created order.created, user.created
* All topics

Delayed Events

Event scheduling for deferred delivery.

Include the deliver_at field with a future ISO 8601 timestamp. The event is persisted immediately but delivery is deferred until the specified timestamp.

curl -X POST "https://jobcelis.com/api/v1/events" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"topic":"reminder","deliver_at":"2026-12-25T00:00:00Z","message":"Merry Christmas"}'

Batch Events

Multiple event submission in a single API request.

POST /api/v1/events/batch

Submits an array of event objects in a single request.

curl -X POST "https://jobcelis.com/api/v1/events/batch" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"events":[{"topic":"a","data":1},{"topic":"b","data":2}]}'
Response 202 Accepted
{
  "accepted": 2,
  "rejected": 0,
  "events": [
    {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "topic": "a",
      "payload": 1,
      "status": "pending",
      "occurred_at": "2026-03-07T14:30:00Z",
      "payload_hash": "e3b0c44298fc1c14...",
      "inserted_at": "2026-03-07T14:30:00Z"
    },
    {
      "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
      "topic": "b",
      "payload": 2,
      "status": "pending",
      "occurred_at": "2026-03-07T14:30:00Z",
      "payload_hash": "a1b2c3d4e5f67890...",
      "inserted_at": "2026-03-07T14:30:00Z"
    }
  ]
}

Cursor Pagination

Efficient cursor-based pagination for large result sets.

Paginated endpoints use cursor-based pagination. Use the next_cursor value from the response as the cursor parameter in subsequent requests.

curl "https://jobcelis.com/api/v1/events?limit=20&cursor=NEXT_CURSOR" \
  -H "Authorization: Bearer YOUR_TOKEN"

Webhook Templates

Pre-configured webhook templates.

GET /api/v1/webhooks/templates

Lists available webhook templates.

curl "https://jobcelis.com/api/v1/webhooks/templates" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK
{
  "templates": [
    {
      "name": "Slack Notification",
      "url": "https://hooks.slack.com/services/...",
      "topics": ["order.created", "payment.completed"],
      "headers": {"Content-Type": "application/json"}
    },
    {
      "name": "Email Alert",
      "url": "https://api.example.com/email-hook",
      "topics": ["user.signup"],
      "headers": {}
    }
  ]
}

IP Allowlist

API access restriction via IP allowlisting.

Configure IP allowlisting for the project API key. Only requests from authorized IPs are accepted. Configured via project settings.

Simulator

Webhook validation without submitting real events.

POST /api/v1/simulate

Simulates event delivery to validate webhook configuration.

curl -X POST "https://jobcelis.com/api/v1/simulate" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"topic":"order.created","payload":{"test":true}}'
Response 200 OK
{
  "simulation": true,
  "matching_webhooks": 1,
  "results": [
    {
      "id": "b3e7c8a1-4f2d-4e9a-8c1b-5d6f7a8b9c0d",
      "url": "https://example.com/hook",
      "topics": ["order.*"]
    }
  ]
}
The simulator does not persist events or generate actual deliveries. It shows which webhooks would receive the event and the resulting transformed payload.

Idempotency Keys

Prevents duplicate event processing using client-provided unique keys.

Send idempotency_key in the body or the X-Idempotency-Key header to deduplicate events. If an event with the same key already exists in the project, the existing event is returned without creating a new one.

# Option 1: idempotency_key in the request body
curl -X POST "https://jobcelis.com/api/v1/send" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"topic":"order.created","amount":150,"idempotency_key":"order-123-abc"}'
# Option 2: X-Idempotency-Key as header
curl -X POST "https://jobcelis.com/api/v1/send" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "X-Idempotency-Key: order-123-abc" \
  -d '{"topic":"order.created","amount":150}'
The X-Idempotency-Key header takes precedence over the body field. Keys automatically expire after several days.

External alerts

Receive notifications outside the dashboard when something fails with your webhooks.

Configure notification channels to receive alerts via email, Slack, Discord, or meta-webhook when critical events occur.

Channel Settings
email Recipient email address
slack Slack Incoming Webhook URL
discord Discord Webhook URL
webhook URL of an HTTP endpoint that receives alerts (meta-webhook)
PUT /api/v1/notification-channels

Create or update a notification channel.

curl -X PUT "https://jobcelis.com/api/v1/notification-channels" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"channel":"slack","config":{"webhook_url":"https://hooks.slack.com/services/..."},"events":["webhook_failing","circuit_open"]}'
POST /api/v1/notification-channels/test

Send a test notification to the configured channel.

curl -X POST "https://jobcelis.com/api/v1/notification-channels/test" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"channel":"slack"}'
GET /api/v1/notification-channels

List the configured notification channels.

curl "https://jobcelis.com/api/v1/notification-channels" \
  -H "Authorization: Bearer YOUR_API_KEY"
Response 200 OK
{
  "data": {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "project_id": "p1a2b3c4-d5e6-7890-abcd-ef1234567890",
    "email_enabled": true,
    "email_address": "alerts@example.com",
    "slack_enabled": true,
    "slack_webhook_url": "https://hooks.slack.com/••••••",
    "discord_enabled": false,
    "discord_webhook_url": null,
    "meta_webhook_enabled": false,
    "meta_webhook_url": null,
    "meta_webhook_secret": null,
    "event_types": ["webhook_failing", "circuit_open"],
    "inserted_at": "2026-03-07T14:30:00Z",
    "updated_at": "2026-03-07T14:30:00Z"
  }
}
DELETE /api/v1/notification-channels

Delete the notification channel configuration.

curl -X DELETE "https://jobcelis.com/api/v1/notification-channels" \
  -H "Authorization: Bearer YOUR_API_KEY"
Response 204 No Content
# 204 No Content (empty response body)

Embeddable Portal

JavaScript widget for your end-users to manage their own webhooks.

Generate an embed token with specific scopes and use the JS widget so your clients can configure webhooks and view deliveries without accessing your dashboard.

POST /api/v1/embed/tokens

Generate a new embed token.

curl -X POST "https://jobcelis.com/api/v1/embed/tokens" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"project_id":"PROJECT_ID","name":"My Portal"}'
GET /api/v1/embed/tokens

List the embed tokens for the project.

curl "https://jobcelis.com/api/v1/embed/tokens" \
  -H "Authorization: Bearer YOUR_API_KEY"
Response 200 OK
{
  "data": [
    {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "prefix": "emb_abc",
      "name": "My Portal",
      "status": "active",
      "scopes": ["webhooks:read", "webhooks:write"],
      "allowed_origins": ["https://example.com"],
      "metadata": {},
      "expires_at": null,
      "inserted_at": "2026-03-07T14:30:00Z"
    }
  ]
}
DELETE /api/v1/embed/tokens/:id

Revoke an embed token.

curl -X DELETE "https://jobcelis.com/api/v1/embed/tokens/TOKEN_ID" \
  -H "Authorization: Bearer YOUR_API_KEY"
Response 200 OK
{
  "status": "revoked"
}

Integrate the widget

<script src="https://jobcelis.com/embed.js"></script>
<div id="jobcelis-portal"></div>
<script>
  JobcelisPortal.init({
    token: "emb_...",
    container: "#jobcelis-portal",
    baseUrl: "https://jobcelis.com",
    locale: "en"
  });
</script>
Method Path Description
GET /api/v1/embed/webhooks List webhooks
POST /api/v1/embed/webhooks Create webhook
GET /api/v1/embed/deliveries List deliveries
POST /api/v1/embed/deliveries/:id/retry Retry delivery
The embed token is only shown once when created. Available scopes: webhooks:read, webhooks:write, deliveries:read, deliveries:retry.

Outbound Rate Limiting

Control webhook delivery speed to avoid overwhelming receiver servers.

Each webhook can have its own rate limit. If not configured, default values apply.

curl -X PATCH "https://jobcelis.com/api/v1/webhooks/WEBHOOK_ID" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"rate_limit":{"max_per_second":100,"max_per_minute":5000}}'
When a webhook reaches its limit, pending deliveries are automatically queued and retried within seconds.

Prometheus Metrics

Prometheus-compatible /metrics endpoint for professional monitoring with Grafana.

Available metrics:

Counters

  • jobcelis_events_created_total — Events created (by project, topic)
  • jobcelis_deliveries_success_total — Successful deliveries (by project, webhook, topic)
  • jobcelis_deliveries_failed_total — Failed deliveries (by project, webhook, topic)

Gauges

  • jobcelis_webhooks_active — Active webhooks
  • jobcelis_circuit_breakers_open — Open circuit breakers
  • jobcelis_deliveries_pending — Pending deliveries in queue

Histograms

  • jobcelis_delivery_latency_milliseconds — Delivery latency (by project, webhook, topic)
Metrics are exposed on a separate port. Configure your Prometheus scraper pointing to the metrics port.

Webhook testing

Send a test event to a webhook without creating a real event in the project.

Use the test endpoint to verify that the receiver is configured correctly. A test payload with type webhook.test is sent, the HMAC signature is computed if the webhook has a secret, and the response code and latency are returned.

POST /api/v1/webhooks/:id/test

Send a test event to a webhook.

curl -X POST https://jobcelis.com/api/v1/webhooks/WEBHOOK_ID/test \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK
{
  "success": true,
  "status": 200,
  "latency_ms": 145,
  "webhook_id": "abc-123"
}
The test event is not stored and does not generate real deliveries. You can also send tests from the dashboard using the paper airplane button on the webhook row.

Data retention

Configure automatic retention per project and execute selective manual purges.

Automatic retention

Configure how many days to retain each data type. The system automatically purges old records weekly. A value of 0 means unlimited retention.

GET /api/v1/retention

View the current retention policy for the project.

curl "https://jobcelis.com/api/v1/retention" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response 200 OK
{
  "retention_days": null,
  "retention_policy": {
    "events_days": 90,
    "deliveries_days": 30,
    "audit_logs_days": 365
  }
}
PATCH /api/v1/retention

Update retention policy.

curl -X PATCH https://jobcelis.com/api/v1/retention \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"events_days": 90, "deliveries_days": 30, "audit_logs_days": 365}'
Response 200 OK
{
  "retention_policy": {
    "events_days": 90,
    "deliveries_days": 30,
    "audit_logs_days": 365
  }
}

Manual purge

Delete data selectively by type, date, topic, and status. Use the preview endpoint to see how many records would be deleted before executing.

POST /api/v1/purge/preview

Purge preview (without deleting).

curl -X POST https://jobcelis.com/api/v1/purge/preview \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"type": "deliveries", "older_than": "2025-01-01", "status": "failed"}'
Response 200 OK
{
  "type": "deliveries",
  "count": 1247,
  "older_than": "2025-01-01"
}
POST /api/v1/purge

Execute data purge.

curl -X POST https://jobcelis.com/api/v1/purge \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"type": "deliveries", "older_than": "2025-01-01", "status": "failed"}'
Response 200 OK
{
  "type": "deliveries",
  "deleted_count": 1247,
  "older_than": "2025-01-01"
}

Available purge types

Type Optional filters
events topic
deliveries topic, status
audit_logs
dead_letters
Data purge is irreversible. Always use the preview endpoint before executing to confirm the number of affected records.

SDKs (12 languages)

Official SDKs for major programming languages.

All SDKs provide complete API coverage. Select the preferred language:

Send an event

# Install
npm install @jobcelis/sdk

# Usage
const { JobcelisClient } = require('@jobcelis/sdk');

const client = new JobcelisClient({ apiKey: 'YOUR_API_KEY' });

await client.sendEvent({
  topic: 'order.created',
  payload: { order_id: '12345', amount: 99.99 },
});

CLI

Command-line interface for managing events, webhooks, jobs, and platform resources.

@jobcelis/cli on npm

npm install -g @jobcelis/cli
export JOBCELIS_API_KEY="YOUR_API_KEY"

# Send an event
jobcelis events send --topic order.created --payload '{"id":"123"}'

# List events
jobcelis events list --limit 10

# List webhooks
jobcelis webhooks list

# Create a webhook
jobcelis webhooks create --url https://example.com/hook --topics "order.*"

# Check platform status
jobcelis status

Webhook Signature Verification

HMAC signature verification of each delivery to confirm authenticity.

Each delivery includes an HMAC signature in the X-Signature header. Always verify signatures to confirm the request originated from Jobcelis.

Signature algorithm

  1. Compute HMAC-SHA256 of the raw body using the webhook secret
  2. Encode the result in Base64 without padding
  3. Sent in the header as: X-Signature: sha256=<base64>

Verification function by language

# Install
npm install @jobcelis/sdk

# Usage
const crypto = require('crypto');

function verifySignature(secret, body, signature) {
  if (!signature.startsWith('sha256=')) return false;
  const received = signature.slice(7);
  const expected = crypto
    .createHmac('sha256', secret)
    .update(body)
    .digest('base64')
    .replace(/=+$/, '');
  const a = Buffer.from(received, 'base64');
  const b = Buffer.from(expected, 'base64');
  if (a.length !== b.length) return false;
  return crypto.timingSafeEqual(a, b);
}

Framework middleware examples

Express.js (Node.js)
const crypto = require('crypto');

app.post('/webhook', express.raw({ type: '*/*' }), (req, res) => {
  const signature = req.headers['x-signature'];
  const body = req.body.toString();
  if (!verifySignature(process.env.WEBHOOK_SECRET, body, signature)) {
    return res.status(401).send('Invalid signature');
  }
  const event = JSON.parse(body);
  // Process event...
  res.sendStatus(200);
});
FastAPI (Python)
from fastapi import FastAPI, Request, HTTPException

@app.post("/webhook")
async def webhook(request: Request):
    body = (await request.body()).decode()
    signature = request.headers.get("x-signature", "")
    if not verify_signature(WEBHOOK_SECRET, body, signature):
        raise HTTPException(status_code=401, detail="Invalid signature")
    event = await request.json()
    # Process event...
    return {"ok": True}
Gin (Go)
func webhookHandler(c *gin.Context) {
    body, _ := io.ReadAll(c.Request.Body)
    signature := c.GetHeader("X-Signature")
    if !jobcelis.VerifyWebhookSignature(secret, string(body), signature) {
        c.JSON(401, gin.H{"error": "invalid signature"})
        return
    }
    // Process event...
    c.JSON(200, gin.H{"ok": true})
}
Phoenix (Elixir)
defmodule MyAppWeb.WebhookController do
  use MyAppWeb, :controller

  def handle(conn, _params) do
    {:ok, body, conn} = Plug.Conn.read_body(conn)
    sig = Plug.Conn.get_req_header(conn, "x-signature") |> List.first("")
    if Jobcelis.WebhookVerifier.verify(secret, body, sig) do
      event = Jason.decode!(body)
      # Process event...
      json(conn, %{ok: true})
    else
      conn |> put_status(401) |> json(%{error: "invalid signature"})
    end
  end
end
Laravel (PHP)
Route::post('/webhook', function (Request $request) {
    $body = $request->getContent();
    $signature = $request->header('X-Signature', '');
    if (!WebhookVerifier::verify($secret, $body, $signature)) {
        return response()->json(['error' => 'invalid signature'], 401);
    }
    $event = json_decode($body, true);
    // Process event...
    return response()->json(['ok' => true]);
});
Spring Boot (Java)
@PostMapping("/webhook")
public ResponseEntity<Map<String, Object>> webhook(
        @RequestBody String body,
        @RequestHeader("X-Signature") String signature) {
    if (!WebhookVerifier.verify(secret, body, signature)) {
        return ResponseEntity.status(401).body(Map.of("error", "invalid signature"));
    }
    // Process event...
    return ResponseEntity.ok(Map.of("ok", true));
}
ASP.NET (C#)
[HttpPost("webhook")]
public async Task<IActionResult> Webhook() {
    using var reader = new StreamReader(Request.Body);
    var body = await reader.ReadToEndAsync();
    var signature = Request.Headers["X-Signature"].FirstOrDefault() ?? "";
    if (!WebhookVerifier.Verify(secret, body, signature))
        return Unauthorized(new { error = "invalid signature" });
    // Process event...
    return Ok(new { ok = true });
}
Rails (Ruby)
class WebhooksController < ApplicationController
  skip_before_action :verify_authenticity_token

  def handle
    body = request.raw_post
    signature = request.headers["X-Signature"] || ""
    unless Jobcelis::WebhookVerifier.verify(
      secret: ENV["WEBHOOK_SECRET"], body: body, signature: signature
    )
      return render json: { error: "invalid signature" }, status: 401
    end
    event = JSON.parse(body)
    # Process event...
    render json: { ok: true }
  end
end

CLI verification

jobcelis verify-signature \
  --secret "whsec_your_secret" \
  --body '{"topic":"order.created","data":{"id":"123"}}' \
  --signature "sha256=abc123..."
Always use constant-time comparison. Do not use == or === operators to verify signatures. Verify the raw request body, not a re-serialized version.

Account Lockout

Protection against brute force attacks.

After multiple failed authentication attempts within a short period, the account is temporarily locked. Provides protection against brute force attacks and compromised credentials.

Session Management

Active session control.

Web sessions use encrypted cookies with inactivity timeouts. Sessions automatically terminate after a period of inactivity.

MFA / TOTP

Two-factor authentication

Enable two-factor authentication from the account page. Use a compatible authenticator application (Google Authenticator, Authy, etc.) to scan the QR code. Each login requires the password and the TOTP code from the application.

MFA activation generates one-time backup codes. These must be stored securely to allow access in case of device loss.

Password Policy

Password requirements policy.

  • Minimum length required
  • Must include uppercase, lowercase and numbers
  • Special characters recommended
  • Passwords are stored with memory-hard secure hashing

Data Encryption

Personal data protection.

Personal data (email, name) is encrypted at rest with industry-standard encryption. Email lookups use deterministic hashing, avoiding the need to decrypt during queries.

Encryption at rest protects data even in the event of direct database access. Only the application can decrypt the data.

Circuit Breaker

Automatic protection for unstable webhooks.

If a webhook fails repeatedly, the circuit breaker temporarily disables it to prevent failure cascades. When the endpoint recovers, the webhook is automatically re-enabled.

Breach Detection

Continuous security monitoring.

The system continuously monitors for anomalous patterns: multiple failed authentication attempts, access from unusual locations, and other indicators of potential security incidents.

Event Integrity

Event integrity and immutability guarantee.

Each event receives a unique cryptographic hash at creation time. Enables verification that content has not been altered. Events are stored immutably.

Additionally, each event supports an optional idempotency_key for duplicate prevention. If multiple events share the same idempotency_key, only the first is processed.

Monitoring

Automated platform monitoring.

The platform is continuously monitored. Current status is available on the status page (/status). Monitored components include the database, the processing system, and the cache layer.

Backups

Automatic backups.

Automated backups are performed periodically. Backups are stored securely and encrypted. In the event of an incident, data can be restored expeditiously.

GDPR / RGPD

Data protection rights.

Jobcelis is GDPR/RGPD compliant. Users have the following data protection rights:

  • Access: Export all your personal data (GET /api/v1/me/data)
  • Rectification: Update your profile from the account page
  • Description Restrict processing (POST /api/v1/me/restrict)
  • Objection: Object to processing (POST /api/v1/me/object)
  • Portability: Export data in standard JSON format
GET /api/v1/me/data

Exports all your personal data stored on the platform (GDPR Article 15 — right of access).

curl "https://jobcelis.com/api/v1/me/data" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
Response 200 OK
{
  "data": {
    "profile": {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "email": "user@example.com",
      "name": "Jane Doe",
      "role": "user",
      "inserted_at": "2026-01-10T08:00:00Z"
    },
    "consents": [...],
    "activity": [...]
  }
}
POST /api/v1/me/restrict

Restricts the processing of your personal data (GDPR Article 18). Requires password confirmation.

curl -X POST "https://jobcelis.com/api/v1/me/restrict" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"password": "YOUR_PASSWORD"}'
Response 200 OK
{
  "status": "restricted",
  "restricted_at": "2026-03-10T12:00:00Z"
}
DELETE /api/v1/me/restrict

Lifts the data processing restriction, restoring active status.

curl -X DELETE "https://jobcelis.com/api/v1/me/restrict" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
Response 200 OK
{
  "status": "active"
}
POST /api/v1/me/object

Registers an objection to the processing of your personal data (GDPR Article 21).

curl -X POST "https://jobcelis.com/api/v1/me/object" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
Response 200 OK
{
  "processing_consent": false
}
DELETE /api/v1/me/object

Withdraws the processing objection, restoring processing consent.

curl -X DELETE "https://jobcelis.com/api/v1/me/object" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
Response 200 OK
{
  "processing_consent": true
}

HTTP Status Codes

Standard HTTP status codes used by the API.

Code Meaning
200 OK
201 Created
204 No Content
400 Bad Request
401 Unauthorized
403 Forbidden
404 Not Found
409 Conflict
422 Unprocessable Entity
429 Too Many Requests
500 Internal Server Error

Error responses

Standard format for errors returned by the API.

Failed requests return a JSON response with an "error" field describing the issue.

Common error examples

// 400 Bad Request — missing or invalid parameters
{"error": "Missing required field: topic"}

// 401 Unauthorized — invalid or missing API key
{"error": "Invalid API key"}

// 404 Not Found — resource does not exist
{"error": "Event not found"}

// 422 Unprocessable Entity — validation error
{"error": "URL must start with https://"}

// 429 Too Many Requests — rate limit exceeded
{"error": "Rate limit exceeded. Try again later."}
The "error" field always contains a human-readable string. Some endpoints may include additional "details" fields with specific error information.

Response Headers

Headers included in API responses.

Header Description
X-Request-Id Unique request ID for debugging
X-RateLimit-Limit Request limit per window
X-RateLimit-Remaining Remaining requests in the window
X-RateLimit-Reset Rate limit reset timestamp

Health Check

Endpoint for external monitoring.

GET /health

Returns HTTP 200 if the platform is operational.

curl "https://jobcelis.com/health"
Response 200 OK
{
  "status": "healthy",
  "timestamp": "2026-03-07T14:30:00Z"
}

API Key Scopes

Granular permissions for API keys.

Configure scopes to restrict API key permissions. Available scopes:

events:read — Read events
events:write — Create account
webhooks:read — Read webhooks
webhooks:write — Create webhook
jobs:read — Read jobs
jobs:write — Create/edit jobs
admin — Full access