# API keys and webhooks

Source: https://kirora.io/docs/guides/integrations/api-keys-and-webhooks

Create, scope, rotate and revoke API keys, and send your workspace's events to your own systems with webhooks.

API keys let your website, app or other tools call Kirora, and webhooks send Kirora's events, such as deliveries, unsubscribes and form signups, to a URL of yours. Both live on the **Developer** page, and both are available on every plan.

Only admins, developers and the owner can create, change or revoke keys and manage webhooks. Anyone else who opens **API keys** sees *Only owners, admins and developers can see and manage API keys. Ask one of them for a key if you need one.*

This guide covers the dashboard. For code, point your developer to the [API quickstart](https://kirora.io/docs/api/quickstart), [Authentication](https://kirora.io/docs/api/reference/authentication) and the [webhooks guide](https://kirora.io/docs/api/webhooks).

## Kinds of key

The **Kind** column on **Developer › API keys** shows what each key is for:

| Kind | What it's for |
| --- | --- |
| **Integration** | Your own server, or a tool such as Zapier, Make, n8n or Segment. Created with **New API key**, or from that tool's page under **Integrations**, which labels the key *For Zapier* (and so on). |
| **Agent** | An AI assistant such as Claude or Cursor. Created with **New agent key** on **Agent access**. It can read and draft, but never send. See [Connect Claude, Cursor or another AI assistant](https://kirora.io/docs/guides/kiro-ai/use-kiro-ai-with-claude-or-cursor). |
| **Partner** | A platform that runs Kirora workspaces for its own customers. **New partner key** only appears in a partner workspace. |

An AI app you connect by signing in, rather than with a key, is listed here too, as an **Agent** key named after the app with *(connected app)*. See [Connected apps](https://kirora.io/docs/guides/integrations/connected-apps).

## Create an API key

1. Go to **Developer › API keys** and choose **New API key**.
2. Enter a **Name** after the app or environment that will use it, such as *Mobile app production*.
3. Under **Permissions**, tick only what this application needs. Each permission shows its technical name, such as `events:write`, and what it allows. A write permission includes its read. **All permissions** gives full access, so keep it for an application you trust with everything.
4. Choose when it **Expires**: **In 30 days**, **In 90 days** (the default), **In one year** or **No expiry**.
5. Optionally, list **Allowed addresses**: the IP addresses or CIDR ranges, such as *203.0.113.0/24*, that may use the key. Leave it empty to allow any address.
6. Choose **Create key**.

Kirora shows the full key once, under **Copy your key now**. Copy it into your server's secret settings, then choose **Done**. After that, the list only shows a short hint of the key so you can tell keys apart.

> [!WARNING]
> Keep keys on your server. Never put one in a website, an app bundle or a public code repository. For your website and apps, use the SDK's public key instead (see [SDK keys](#sdk-keys)).

A key keeps the permissions it was created with. To give an application different permissions, create a new key and revoke the old one.

### If you're a developer

A key you create or rotate can have every read permission, but a [hidden attribute](https://kirora.io/docs/guides/contacts/attributes#hide-sensitive-attributes) shows as **Hidden** to it, as it does to you. It can only change sending domains, webhooks, contacts, events and attribute definitions: what connecting your app or another tool needs. **Permissions** lists only those, and a preset starts without the rest. Sending, activating journeys, editing content and deleting need a key from an admin or the owner. You also can't rotate a key that holds more than you could give it.

## Manage a key

The list shows each key's **Permissions**, when it **Expires**, when it was **Last used** and its **Status**: **Active**, **Expired** or **Revoked**. Revoked keys are hidden under the list until you choose to show them, for example **Show 2 revoked keys**.

Each key's menu has:

- **View requests**: opens the **Request log** on this key's calls, with its history (created, rotated, revoked) above them. Filter by **Errors only** to see what failed.
- **Where it can be used**: change the key's **Allowed addresses**. From the next request, calls from anywhere else are refused.
- **Rotate secret**: issue a new secret for the same key.
- **Revoke key**: stop the key for good.

### Rotate a key

Rotating gives the key a new secret with the same permissions and expiry, so you can replace a secret without downtime.

1. Choose **Rotate secret** from the key's menu.
2. Under **Old secret keeps working for**, choose **Stop it now**, **1 hour**, **24 hours** (the default) or **7 days**.
3. Choose **Rotate key**, and copy the new secret.

Deploy the new secret before the old one stops. Until then, the key's row shows *Old secret works until* that time. Rotating again stops the previous secret at once.

An expired key can't be rotated. Create a new key with a future expiry instead.

### Revoke a key

Choose **Revoke key** from the key's menu, then **Revoke key** to confirm. Applications using it lose access at once, for good, and any old secret from a rotation stops too.

## SDK keys

The **SDK** tab holds the two keys Kirora's web SDK needs to track what signed-in people do on your website and to send web push notifications:

- **Public key**: goes in your website. It's safe to share.
- **Secret key**: stays on your server, where it signs a token for each signed-in person. It's shown once.

An owner, admin or developer chooses **Set up the SDK** to make both. Later, they can:

- **Rotate secret key**: the current secret keeps working for 24 hours.
- **Replace public key**: websites using the current key stop working at once, so update them straight away.

The **Website** row shows whether events are arriving, for example *Connected · last event 2 hours ago*. The iOS, Android, React Native and Flutter SDKs are **Coming soon**. For setup, see the [web SDK guide](https://kirora.io/docs/sdks/web) and [Set up push notifications](https://kirora.io/docs/guides/getting-started/set-up-push).

## Add a webhook endpoint

A webhook sends each event you choose to an HTTPS address on your server as it happens, so your systems don't have to keep asking Kirora for changes.

1. Go to **Developer › Webhooks** and choose **Add endpoint**.
2. Enter the **Endpoint URL**, such as *https://example.com/webhooks/kirora*. It must start with `https://` and point to a public address.
3. Under **Events**, tick the events to receive. **Message delivered** and **Message bounced** are ticked to start with.
4. Choose **Add endpoint**.
5. Copy the signing secret under **Copy the signing secret now**. Your server uses it to check that each request really came from Kirora. It's shown once.

The events you can choose:

| Contacts and forms | Campaigns and journeys | Messages |
| --- | --- | --- |
| **Contact created**, **Contact unsubscribed**, **Consent changed**, **Form submitted** | **Campaign sent**, **Contact joined a journey** | **Message sent**, **Message delivered**, **Message bounced**, **Marked as spam**, **Message opened**, **Message clicked**, **Message failed**, **Message skipped** |

Each URL can have only one webhook. If you add the same URL again, Kirora says *This URL already has a webhook. Edit that one's events instead.* For each event's contents, see the [webhook events reference](https://kirora.io/docs/api/reference/webhooks).

## Test and manage an endpoint

- **Send test event** sends a `webhook.test` event to the endpoint. It appears under **Recent deliveries**. Only an **Active** endpoint can be tested.
- **Edit** changes the URL or the events.
- **Pause** stops new events going to the endpoint. Deliveries already waiting are sent when you choose **Resume**, but events that happen while it's paused aren't sent later. To catch up, read what changed through the [API](https://kirora.io/docs/api/webhooks#retries).
- **Rotate secret** issues a new signing secret. The old one keeps working for 24 hours, so your server can accept either while you switch.
- **Delete** removes the endpoint and its delivery records for good.

An endpoint made by a tool such as Zapier shows *Made by Zapier*. Its status is **Active**, **Paused** or **Turned off**.

## Recent deliveries

**Recent deliveries** lists each attempt across all your endpoints, with its **Event**, **Endpoint**, **Status** (**Waiting**, **Delivered** or **Failed**), the **Response** your server gave, such as *HTTP 500* or *No reply within 5 seconds*, and the number of **Attempts**.

Choose **Details** to see the **Request body** Kirora sent and the first 1 KB of your server's reply. On a failed delivery, choose **Send again** to resend the same event once your server is fixed.

## Retries and turned-off endpoints

Your server must reply with a 2xx status within 5 seconds. If it doesn't, Kirora tries again, waiting a minute at first and then longer, for about 45 hours in all. Deliveries arrive at least once, so your developer should use each event's ID to ignore repeats.

- **After five failures in a row**, Kirora holds the endpoint back for a few minutes, then up to an hour, so a broken endpoint doesn't build a queue. Its status shows *Paused after repeated failures until* a time. Choose **Retry now** to try straight away.
- **Kirora turns an endpoint off** when it answers *410 Gone*, or when an event has failed its last retry and the endpoint accepted nothing else in that time. Admins, developers and the owner get a notification, and the page says the endpoint was turned off. Deliveries already waiting stay waiting; events that happen while it's off aren't sent. Fix the endpoint, then choose **Resume**.

See [Troubleshoot integrations](https://kirora.io/docs/guides/integrations/troubleshoot-integrations#webhook-deliveries-fail) for the common causes.

## Next steps

- [Connected apps](https://kirora.io/docs/guides/integrations/connected-apps)
- [Troubleshoot integrations](https://kirora.io/docs/guides/integrations/troubleshoot-integrations)
- [Authentication](https://kirora.io/docs/api/reference/authentication)
- [Webhooks guide](https://kirora.io/docs/api/webhooks)