Skip to content

Extension API

Extensions interact with Kiket via the REST API using API keys scoped to the project and permissions declared in the manifest.

Authentication

  • Runtime tokens (preferred): The platform injects a short-lived runtime token into each webhook payload. Send it via X-Kiket-Runtime-Token: <token>โ€”the official SDKs do this automatically.
  • Workspace tokens: For server-to-server calls outside webhook context (e.g., extensions receiving external webhooks), use Authorization: Bearer <workspace_token>.
  • Both runtime tokens and workspace tokens carry scopes (e.g., read:issues, write:comments) and requests outside the scope return 403.

Base URL

https://kiket.dev/api/v1/ext

Endpoints

Method Path Description Required Scope
GET /issues List issues visible to the project read:issues
GET /issues/:key Retrieve an issue by key read:issues
POST /issues Create an issue (titles, hierarchy, custom fields) write:issues
POST /issues/:key/comments Add a comment write:comments
POST /issues/:key/transitions Trigger a workflow transition write:issues
PATCH /issues/:key Update fields (labels, custom fields, assignee, parent) write:issues
GET /projects/:slug/workflows Fetch workflow metadata read:workflows
GET /projects/:slug/boards Fetch board definitions and provenance read:boards
POST /analytics/events Inject custom analytics events write:analytics
GET /custom_data/:module/:table List custom data records (project_id required) custom_data.read
GET /custom_data/:module/:table/:id Retrieve a single custom data record custom_data.read
POST /custom_data/:module/:table Create a custom data record custom_data.write
PATCH /custom_data/:module/:table/:id Update a custom data record custom_data.write
DELETE /custom_data/:module/:table/:id Delete (soft delete) a record custom_data.write
GET /sla/events List SLA alerts for the installation (project_id, issue_id, state, limit) read:issues

See the Custom Data guide for end-to-end examples (manifest, API, CLI, and SDK usage).

Command Palette Bridge

For in-app integrations (Stimulus/React controllers) the platform exposes session-authenticated endpoints that mirror the manifest-defined command palette contributions:

Method Path Description
GET /projects/:id/command_palette List commands available to the current user/project.
POST /projects/:id/command_palette_run Execute a command and forward the payload to the extension runtime.

Use these endpoints when building UI that launches extension commands directly from the browser. Calls inherit the current user's permissions, so commands respect role-based access automatically.

Pagination & Filtering

  • Use page and per_page query params for pagination (per_page max 100).
  • Filter issues with state, label, assignee, hierarchy (parent_id, root_id), or custom field (e.g., custom_fields[customer]=acme).

Rate Limits

  • Default: 600 requests per minute per installation.
  • Responses include X-RateLimit-Remaining and Retry-After headers.

External Webhook Routing

Extensions can receive webhooks from external providers (Mailjet, Twilio, Slack, etc.) via per-installation webhook URLs. This eliminates the need for static API keysโ€”Kiket issues a runtime token for each incoming webhook.

How It Works

  1. Each installation gets a unique webhook URL:

    https://kiket.dev/webhooks/ext/{webhook_token}
    https://kiket.dev/webhooks/ext/{webhook_token}/{action}
    

  2. Configure the external provider to send webhooks to this URL (e.g., Mailjet Parse API, Twilio webhook settings).

  3. Kiket forwards the webhook to your extension with a runtime token, triggering an external.webhook.* event.

  4. Your extension processes the payload using the authenticated context.

Retrieving the Webhook URL

Extensions can retrieve their webhook URL via the API:

curl -H "X-Kiket-Runtime-Token: rt_xxx" \
     "https://kiket.dev/api/v1/ext/webhook_url"

Response:

{
  "webhook_url": "https://kiket.dev/webhooks/ext/wh_abc123xyz",
  "webhook_base_url": "https://kiket.dev/webhooks/ext/wh_abc123xyz",
  "actions": {
    "inbound_email": "https://kiket.dev/webhooks/ext/wh_abc123xyz/inbound_email"
  }
}

Rotating the Webhook Token

If the webhook token is compromised, rotate it:

curl -X POST -H "X-Kiket-Runtime-Token: rt_xxx" \
     "https://kiket.dev/api/v1/ext/webhook_url/rotate"

Handling External Webhooks in SDK

Register a handler for the external.webhook.* event:

sdk.register('external.webhook.inbound_email', version: 'v1') do |payload, context|
  # payload contains the raw external provider data
  provider_data = payload['body']
  headers = payload['headers']

  # Process and call Kiket API with authenticated context
  context[:client].post('/api/v1/ext/inbound_emails', {
    inbound_email: normalize_payload(provider_data)
  })

  { ok: true }
end
@sdk.webhook("external.webhook.inbound_email", version="v1")
async def handle_external(payload, context):
    provider_data = payload["body"]
    headers = payload["headers"]

    await context.client.post("/api/v1/ext/inbound_emails", {
        "inbound_email": normalize_payload(provider_data)
    })

    return {"ok": True}
sdk.webhook('external.webhook.inbound_email', 'v1')(async (payload, context) => {
  const providerData = payload.body;
  const headers = payload.headers;

  await context.client.post('/api/v1/ext/inbound_emails', {
    inbound_email: normalizePayload(providerData)
  });

  return { ok: true };
});

External Webhook Payload

When Kiket forwards an external webhook, the payload includes:

{
  "event": "external.webhook.inbound_email",
  "authentication": {
    "token_type": "runtime",
    "runtime_token": "rt_xxxxx",
    "expires_at": "2026-01-17T12:34:56Z",
    "scopes": ["ext.api.read", "ext.api.write"]
  },
  "api": {
    "base_url": "https://kiket.dev",
    "runtime_header": "X-Kiket-Runtime-Token"
  },
  "external_webhook": {
    "action": "inbound_email",
    "content_type": "application/json",
    "body": { /* raw payload from external provider */ },
    "headers": { /* headers from external provider */ }
  }
}

Webhook Payloads

Webhook bodies include:

{
  "event": "issue.transitioned",
  "installation": {
    "project": "core-platform",
    "extension_key": "deployment-bot"
  },
  "authentication": {
    "token_type": "runtime",
    "runtime_token": "rt_xxxxx",
    "expires_at": "2025-11-10T12:34:56Z",
    "scopes": ["ext.api.read", "ext.api.write"]
  },
  "api": {
    "base_url": "https://kiket.dev",
    "runtime_header": "X-Kiket-Runtime-Token"
  },
  "issue": {
    "key": "CORE-42",
    "title": "Deploy new release",
    "state": "in_progress",
    "url": "https://kiket.dev/projects/core-platform/issues/CORE-42"
  },
  "transition": {
    "from": "review",
    "to": "in_progress",
    "performed_by": "sasha@example.com"
  }
}

SLA Alerts

  • Use GET /sla/events to list alert history; filter by project_id, issue_id, state, or limit.
  • Real-time updates arrive via the workflow.sla_status webhook. state is one of imminent, breached, or recovered.
{
  "event": "workflow.sla_status",
  "state": "imminent",
  "issue": {
    "id": 42,
    "status": "in_progress",
    "title": "Customer onboarding playbook"
  },
  "sla": {
    "definition_id": 7,
    "status": "in_progress",
    "max_duration_minutes": 120,
    "warning_buffer_minutes": 30
  },
  "metrics": {
    "duration_minutes": 105,
    "overdue_minutes": null
  }
}

Guard Responses

When responding to workflow.before_transition with required: true, return JSON with a status field (allow, deny, or pending). Optional message is shown to the actor, and metadata is persisted alongside approval records. Responses default to allow when omitted; network errors are interpreted as deny. See the building guide for sample payloads.

SDKs

Official SDKs provide batteries-included toolkits for building Kiket extensions. All SDKs include:

  • ๐Ÿ”Œ Webhook handlers with version-aware routing
  • ๐Ÿ” HMAC signature verification for inbound payloads
  • ๐Ÿ”‘ Secret manager for extension secrets
  • ๐ŸŒ Built-in web server (Express, Sinatra, Spring Boot, ASP.NET Core)
  • ๐Ÿ“ฆ Manifest loader with automatic secret hydration from environment
  • ๐Ÿ“Š Telemetry & feedback hooks for metrics collection
  • ๐Ÿงช Testing utilities for webhook handler tests

Installation

pip install kiket-sdk
# or
uv add kiket-sdk

Example

from kiket_sdk import KiketSDK

sdk = KiketSDK(
    webhook_secret="sh_123",
    workspace_token="wk_test",
    extension_id="com.example.marketing",
    extension_version="1.0.0",
)

@sdk.webhook("issue.created", version="v1")
async def handle_issue(payload, context):
    summary = payload["issue"]["title"]
    await context.endpoints.log_event("issue.created", summary=summary)
    await context.secrets.set("WEBHOOK_TOKEN", "abc123")
    return {"ok": True}

if __name__ == "__main__":
    sdk.run(host="0.0.0.0", port=8080)

View Python SDK Documentation

Installation

npm install @kiket/sdk

Example

import { KiketSDK } from '@kiket/sdk';

const sdk = new KiketSDK({
  webhookSecret: 'sh_123',
  workspaceToken: 'wk_test',
  extensionId: 'com.example.marketing',
  extensionVersion: '1.0.0',
});

sdk.webhook('issue.created', 'v1')(async (payload, context) => {
  const summary = payload.issue.title;
  await context.endpoints.logEvent('issue.created', { summary });
  await context.secrets.set('WEBHOOK_TOKEN', 'abc123');
  return { ok: true };
});

sdk.run('0.0.0.0', 8080);

View Node.js SDK Documentation

Installation (Maven)

<dependency>
  <groupId>dev.kiket</groupId>
  <artifactId>kiket-sdk</artifactId>
  <version>0.1.0</version>
</dependency>

Example

import dev.kiket.sdk.KiketSDK;

public class Main {
    public static void main(String[] args) {
        KiketSDK sdk = KiketSDK.builder()
            .webhookSecret("sh_123")
            .workspaceToken("wk_test")
            .extensionId("com.example.marketing")
            .extensionVersion("1.0.0")
            .build();

        sdk.register("issue.created", "v1", (payload, context) -> {
            String summary = (String) ((Map) payload.get("issue")).get("title");
            context.getEndpoints().logEvent("issue.created", Map.of("summary", summary));
            context.getSecrets().set("WEBHOOK_TOKEN", "abc123");
            return Map.of("ok", true);
        });

        sdk.run("0.0.0.0", 8080);
    }
}

View Java SDK Documentation

Installation

gem install kiket-sdk

Example

require 'kiket_sdk'

sdk = KiketSDK.new(
  webhook_secret: 'sh_123',
  workspace_token: 'wk_test',
  extension_id: 'com.example.marketing',
  extension_version: '1.0.0'
)

sdk.register('issue.created', version: 'v1') do |payload, context|
  summary = payload['issue']['title']
  context[:endpoints].log_event('issue.created', summary: summary)
  context[:secrets].set('WEBHOOK_TOKEN', 'abc123')
  { ok: true }
end

sdk.run!(host: '0.0.0.0', port: 8080)

View Ruby SDK Documentation

Installation

dotnet add package Kiket.SDK

Example

using Kiket.SDK;

var sdk = new KiketSDK(new SDKConfig
{
    WebhookSecret = "sh_123",
    WorkspaceToken = "wk_test",
    ExtensionId = "com.example.marketing",
    ExtensionVersion = "1.0.0"
});

sdk.Register("issue.created", "v1", async (payload, context) =>
{
    var summary = payload["issue"]["title"].ToString();
    await context.Endpoints.LogEventAsync("issue.created", new Dictionary<string, object>
    {
        ["summary"] = summary
    });
    await context.Secrets.SetAsync("WEBHOOK_TOKEN", "abc123");
    return new { ok = true };
});

sdk.Run("0.0.0.0", 8080);

View .NET SDK Documentation

Configuration

All SDKs support automatic configuration from: - Environment variables: KIKET_WEBHOOK_SECRET, KIKET_WORKSPACE_TOKEN, KIKET_BASE_URL, KIKET_SECRET_* - Manifest files: extension.yaml or manifest.yaml in project root - Programmatic configuration: passed to SDK constructor

Example manifest:

id: com.example.marketing
version: 1.0.0
delivery_secret: sh_production_secret

settings:
  - key: API_KEY
    secret: true
  - key: MAX_RETRIES
    default: 3
  - key: TIMEOUT_MS
    default: 5000

Publishing to GitHub Packages

All SDKs are configured to publish to GitHub Packages with automated CI/CD:

  • Python: Tag with python-v* (e.g., python-v0.1.0)
  • Node.js: Tag with nodejs-v* (e.g., nodejs-v0.1.0)
  • Java: Tag with java-v* (e.g., java-v0.1.0)
  • Ruby: Tag with ruby-v* (e.g., ruby-v0.1.0)
  • .NET: Tag with dotnet-v* (e.g., dotnet-v0.1.0)

See API Reference for platform-wide endpoints available to first-party clients.