> ## Documentation Index
> Fetch the complete documentation index at: https://doc.codika.io/llms.txt
> Use this file to discover all available pages before exploring further.

# API Keys & Authentication

> Four ways to authenticate — API keys for dashboards and CLI, webhook signatures for external platforms, query parameters for headless services

## Authentication methods

Codika supports four authentication methods on its public API:

|                        | Instance Key (`ck_`)                | Organization Key (`cko_`)          | Webhook Signature (HMAC)                                         | URL Query Param                         |
| ---------------------- | ----------------------------------- | ---------------------------------- | ---------------------------------------------------------------- | --------------------------------------- |
| **Created by**         | Auto-generated per process instance | You create in the Codika dashboard | External platform (Resend, Stripe, etc.)                         | Same `ck_` instance key                 |
| **Scope**              | One specific process instance       | Any instance in the organization   | One specific workflow endpoint                                   | One specific process instance           |
| **Best for**           | Custom dashboards, apps             | CLI, agents, CI/CD                 | External platforms that sign outbound webhooks                   | Platforms that can't set custom headers |
| **Passed via**         | `X-API-Key` header                  | `X-Process-Manager-Key` header     | `webhook-signature` + `webhook-id` + `webhook-timestamp` headers | `?api_key=` in URL                      |
| **Secret on the wire** | Yes                                 | Yes                                | No (only a signature)                                            | Yes (encrypted by HTTPS)                |

**For custom dashboards, use instance keys (`ck_`).** They're auto-generated, scoped to exactly one process instance, and require no setup beyond copying the key.

**For external platforms that sign webhooks** (Resend, Stripe, GitHub, Clerk), use [webhook signature verification](/dashboard/webhook-signatures). The external platform creates the signing secret — you just paste it into Codika.

**For platforms that can't set custom headers** (GCP Pub/Sub, IoT devices, simple webhook senders), use [URL query parameter authentication](#url-query-parameter-authentication).

## Where to find your instance API key

1. Open the Codika dashboard
2. Go to your process instance
3. Open the trigger panel (playground)
4. Find the "Public API Access" section
5. Copy the API key (format: `ck_...`)

The API key is also visible in the cURL examples shown in the trigger panel.

<Warning>
  **Instance API keys are secrets.** Treat them like passwords. Never expose them in client-side code, public repositories, or browser network requests.
</Warning>

## Store keys server-side only

Your custom app should **never** send the API key from the browser. Instead, proxy all Codika calls through your own server-side API routes.

```
Browser → Your API route (server-side, has API key) → Codika Public API
```

### Example: SvelteKit server endpoint

```typescript theme={null}
// src/routes/api/trigger/+server.ts
import { json } from '@sveltejs/kit';
import { CODIKA_API_KEY, PROCESS_INSTANCE_ID } from '$env/static/private';

const TRIGGER_URL = `https://api.codika.io/webhook/${PROCESS_INSTANCE_ID}`;

export async function POST({ request }) {
  const { workflowId, payload } = await request.json();

  const response = await fetch(`${TRIGGER_URL}/${workflowId}`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-API-Key': CODIKA_API_KEY
    },
    body: JSON.stringify({ payload })
  });

  const data = await response.json();
  return json(data);
}
```

### Example: Next.js API route

```typescript theme={null}
// app/api/trigger/route.ts
import { NextResponse } from 'next/server';

const CODIKA_API_KEY = process.env.CODIKA_API_KEY!;
const PROCESS_INSTANCE_ID = process.env.PROCESS_INSTANCE_ID!;
const TRIGGER_URL = `https://api.codika.io/webhook/${PROCESS_INSTANCE_ID}`;

export async function POST(request: Request) {
  const { workflowId, payload } = await request.json();

  const response = await fetch(`${TRIGGER_URL}/${workflowId}`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-API-Key': CODIKA_API_KEY
    },
    body: JSON.stringify({ payload })
  });

  const data = await response.json();
  return NextResponse.json(data);
}
```

## Environment variables

Store these in your `.env` file (gitignored):

```env theme={null}
# Codika integration
CODIKA_API_KEY=ck_your_instance_api_key_here
PROCESS_INSTANCE_ID=your_process_instance_id_here

# Base URLs (same for all instances)
CODIKA_TRIGGER_BASE_URL=https://api.codika.io/webhook
CODIKA_STATUS_BASE_URL=https://api.codika.io/status
```

## Key regeneration

If an instance API key is compromised, you can regenerate it from the Codika dashboard. The old key is immediately invalidated. Update your app's environment variables with the new key.

## When to use org keys instead

Use `cko_` organization keys when your app needs to:

* Access **multiple** process instances (not just one)
* Deploy use cases programmatically
* Read agent skills via the API
* Operate across the organization

For most custom dashboards that serve one use case, `ck_` instance keys are simpler and more secure (narrower scope).

## URL query parameter authentication

Some platforms (GCP Pub/Sub, IoT devices, simple webhook senders) can only configure a URL — they can't set custom HTTP headers. For these, pass your instance API key as a query parameter:

```
POST https://api.codika.io/webhook/{processInstanceId}/{workflowId}?api_key=ck_your_key
```

This uses the same `ck_` instance key and the same validation — just a different delivery method.

<Warning>
  **Prefer headers when possible.** Query parameters can appear in server access logs and monitoring dashboards. Use this method only when the calling platform doesn't support custom headers. HTTPS encrypts the full URL in transit, so the key is protected on the wire.
</Warning>

### When to use query parameter auth

| Platform               | Can set headers? | Recommended auth   |
| ---------------------- | ---------------- | ------------------ |
| Your own dashboard/app | Yes              | `X-API-Key` header |
| Resend, Stripe, GitHub | Yes (HMAC)       | Webhook signatures |
| GCP Pub/Sub push       | No               | Query parameter    |
| Simple IoT webhooks    | No               | Query parameter    |
| Zapier, Make           | Yes              | `X-API-Key` header |
