# The Developers page

> Create, roll and revoke API keys, add webhook endpoints, send test events, read deliveries and replay them, and check the request log, all from the Developers page.

Source: https://docs.amomic.in/console/developers

---

The **Developers** page is where you connect your own systems to Amomic-AI. It has four tabs:

- **API keys**: credentials your backend uses to send messages, place calls and read data.
- **Webhooks**: endpoints where Amomic-AI sends events as they happen.
- **Logs**: the requests your keys made in the last 7 days.
- **Quickstart**: copy-paste examples already set up for your workspace.

**Who can use it:** owners and admins, on every plan. An API key can send messages and place calls on behalf of the whole workspace, so Members don't see **Developers** in the sidebar. If a Member opens the page from a link, they see **Admins only** and nothing else.

![The Developers page as a member sees it: an Admins only message explaining that only owners and admins can manage API keys](https://docs.amomic.in/screens/developers/member-view.light.webp)

The page always opens on **API keys**. Links to a specific tab land there too, so click the tab you need.

This page covers the console. For the API itself, start with [the API overview](/api/overview) and [Your first API call](/start/first-api-call).

## API keys

![The API keys tab listing six keys with masked prefixes, scope badges, last used dates and Active, Expires soon and Revoked statuses, with Roll and Revoke buttons and the base URL footer](https://docs.amomic.in/screens/developers/keys.light.webp)

*Two rows named Helpdesk sync: the key was just rolled, and the old one keeps working until it expires.*

| Column | What it shows |
|---|---|
| **Name** | The name you gave the key. |
| **Key** | A masked prefix such as `amk_live_Vq3tK8…`. Use it to match a key to the one in your server's configuration. The full key is never shown again after creation. |
| **Scopes** | What the key is allowed to do. See [Scopes](/api/scopes). |
| **Last used** | `Today`, `Yesterday`, `N days ago`, a date for anything older than 30 days, or `Never`. It is accurate to the day, not the minute. |
| **Status** | **Active**, **Expires soon** (the old half of a roll, still working), or **Revoked**. |

Under the table is a line with your workspace's **base URL**, the rate limit (`120 requests/minute per key`) and the environment (**Live**). It appears once you have at least one key that isn't revoked.

Revoked keys stay in the list so you can see what existed. They have no actions.

### Create a key

::: steps

::: step Open the dialog

Click **Create key**. With no keys yet, click **Create your first key**.
:::

::: step Name it after where it will run

Enter a **Name** of up to 60 characters, such as `Order service (production)`. The name is how you'll tell keys apart in the list and in the request log, so name the system and environment, not the person.
:::

::: step Choose what it can do

Under **What this key can do**, tick each scope this integration needs. Scopes that change things carry an amber **Write** badge. **Read conversations** and **Read agents** are ticked to start with; untick anything you don't need. **Create key** stays disabled until there is a name and at least one scope.
:::

::: step Copy the key

Click **Create key**. The **Copy your API key** dialog shows the full key once. Copy it into your secret store, tick **I've copied it somewhere safe**, then click **Done**.
:::

:::

![The Create an API key dialog with the name Warehouse dispatch notifier and only Send messages ticked; Write badges mark the scopes that change things](https://docs.amomic.in/screens/developers/create-key.light.webp)

The four campaign and appointment scopes appear in the list as their raw names (`campaigns:read`, `campaigns:write`, `appointments:read`, `appointments:write`) with no description:

| Scope | What it allows |
|---|---|
| `campaigns:read` | Read campaigns, their recipients and outcome reports, and check an audience before launch. Also reads Duesly subscribers and dues. |
| `campaigns:write` | Create, launch, pause, resume and cancel campaigns, and download outcome CSVs. Also adds Duesly subscribers and marks dues paid. |
| `appointments:read`, `appointments:write` | Nothing yet. Don't grant them. |

[Scopes](/api/scopes) lists exactly which endpoints each scope opens.

![The Copy your API key dialog showing a full amk_live key, a warning that it is shown only once, and an unticked I've copied it somewhere safe checkbox with Done disabled](https://docs.amomic.in/screens/developers/copy-key.light.webp)

::: warning The key is shown once
Amomic-AI stores a hash of the key, not the key itself. If you close the dialog without copying it, the key can't be recovered. Roll it to get a new one.
:::

Keys go on your server only. The API sends no CORS headers, so a browser can't call it, and a key in front-end code is a leaked key.

### Roll a key without downtime

Rolling replaces a key while the old one keeps working for 24 hours, so you can deploy the new key at your own pace.

::: steps

::: step Click Roll on the key

There is no confirmation. A replacement key is created straight away with the **same name and scopes**, and the **Copy your API key** dialog opens with it.
:::

::: step Copy and deploy the new key

Copy it, tick the checkbox, click **Done**, and deploy it to your integration.
:::

::: step Watch the old key expire

The list now has two rows with the same name. The new one is **Active**. The old one is **Expires soon** and stops working 24 hours after the roll. Tell them apart by the masked prefix. When the request log shows only the new key in use, you can revoke the old one early.
:::

:::

### Revoke a key

Click **Revoke** on the key. The **Revoke this key?** dialog warns that any request using it will start failing within seconds. Click **Revoke key** to confirm. The console says `Key revoked. Requests using it fail immediately.`

![The Revoke this key? dialog for the BI weekly export key, with Cancel and Revoke key buttons](https://docs.amomic.in/screens/developers/revoke-key.light.webp)

Revoking can't be undone. If you are rotating a key, use **Roll** instead. Revoke when a key may have leaked or its integration is gone.

### Change what a key can do

A key's name and scopes can't be changed in the console. To give an integration more or fewer scopes:

1. **Create key** with the scopes it needs, named after the same integration.
2. Deploy the new key.
3. **Revoke** the old one once the request log shows the new key in use.

**Roll** doesn't help here: the replacement copies the old key's scopes exactly.

## Webhooks

![The Webhooks tab with two enabled endpoints showing Last 200, one listing four event types and one receiving every event type, and a disabled endpoint with Last 503 and a note that it was disabled automatically after 15 consecutive failed deliveries](https://docs.amomic.in/screens/developers/webhooks.light.webp)

Each endpoint shows:

- Its URL, with **Enabled** or **Disabled**.
- **Last 200** (or whatever status your server returned) for the most recent event that finished. An error status shows in amber.
- The events it receives, in plain words, or **Every event type**.
- If it was switched off automatically, the reason, followed by *Fix the endpoint, then re-enable it.*
- The buttons **Test**, **Deliveries**, **Disable** or **Enable**, and a trash icon.

Under the endpoints, **Verifying a delivery** has a ready-made signature check in Node. [Verifying signatures](/webhooks/signatures) covers it in every language.

### Add an endpoint

::: steps

::: step Open the dialog

Click **Add endpoint**, or **Add your first endpoint** if you have none.
:::

::: step Enter the URL

Enter the **Endpoint URL**. It must start with `https://`; plain http is refused.
:::

::: step Pick events

Tick the events to send under **Events to send**. Each shows a plain description and its event name. Leave every box unticked to receive all events, including event types added in future.
:::

::: step Copy the signing secret

Click **Add endpoint**. The **Copy your signing secret** dialog shows the secret for this endpoint, once. Copy it into your secret store before you click **Done**.
:::

:::

![The Add a webhook endpoint dialog with an https URL and three events ticked: a customer sent a message, a message was delivered, read or failed, and a call was read](https://docs.amomic.in/screens/webhooks/add-endpoint.light.webp)

![The Copy your signing secret dialog showing a whsec_ secret for the new endpoint](https://docs.amomic.in/screens/developers/signing-secret.light.webp)

The `ticket.replied` event appears in the list under its event name, with no description. It fires when a reply is added to a ticket; see [Event reference](/webhooks/events).

An endpoint's URL and events can't be edited in the console. To change them, add a new endpoint with the new settings, move your server over to its signing secret, then delete the old endpoint.

### Send a test event

Click **Test**. A `ping` event is queued for that endpoint, signed exactly like a real event, and the console says `Test webhook queued. Open deliveries to see the response.` Open **Deliveries** to see what your server answered.

Use it to prove your signature check before a real event depends on it.

::: warning Tests only reach enabled endpoints
A test on a **Disabled** endpoint is queued but never sent: it stays `queued` in **Deliveries**. Re-enable the endpoint first, then test. A test that fails counts toward the automatic switch-off, just like a real event.
:::

### Read deliveries and replay them

Click **Deliveries** to open **Recent deliveries**: the newest 50 delivery attempts for that endpoint.

![Recent deliveries: a queued ping, a message.received delivered with 200 and its payload expanded, one ticket.created event tried three times — no response, then 502, then 200 on attempt 3 — a lead.created refused with 404, and a call.outcome delivered with 200](https://docs.amomic.in/screens/webhooks/deliveries.light.webp)

| What you see | Meaning |
|---|---|
| ↻ with `queued` | Waiting to be sent. |
| ✓ with a status such as `200` | Your server accepted it. |
| ✗ with a status, or `no response` | That attempt failed. The red line is the error or the start of your server's response. |
| `attempt 2`, `attempt 3` | A retry of the same event. Every attempt is its own row, with the same event id. |
| The milliseconds on the right | How long your server took to answer. |
| **Payload** | Expands to the full event exactly as it was sent. |
| **Replay** | Sends the same event again as a new delivery. |

**How retries work.** An event is retried when your server doesn't answer within 10 seconds, returns `429`, or returns a `5xx`. It is tried at most 4 times. Any other status, including redirects and other `4xx` codes, stops after the first attempt. After 15 events in a row fail, the endpoint is switched off automatically. **Enable** resets that count. [Retries and failures](/webhooks/reliability) covers the details.

**Replay** is on every row that has been sent, failed or not. Use it after fixing your endpoint to resend what it missed. Your handler should already ignore duplicates by event `id`, because a replay sends the same id again. Very old deliveries that predate stored payloads can't be replayed: `This older delivery did not retain a replayable payload.`

### Disable, enable and delete

- **Disable** stops all deliveries to the endpoint and keeps it, with its signing secret. **Enable** turns it back on and clears the failure count.
- The trash icon deletes the endpoint **immediately, with no confirmation**, and its signing secret is gone for good. The console says `Endpoint removed.` If you only want deliveries to stop for a while, use **Disable**.

To bring back an endpoint that was switched off automatically: fix your server, click **Enable**, click **Test**, and check **Deliveries** for a `200`.

## Logs

The **Request log** lists the requests your API keys made, newest first.

![The Request log with fourteen requests from three keys, showing time, method and path, key name, status with error codes such as permission_denied, invalid_argument, not_found and conflict, and duration](https://docs.amomic.in/screens/developers/logs.light.webp)

| Column | What it shows |
|---|---|
| **Time** | When the request arrived, in your browser's local time. |
| **Request** | The method and path, such as `POST /api/v1/messages`. |
| **Key** | The name of the key that made it. |
| **Status** | The HTTP status, plus the error code for a failed request, such as `permission_denied`. |
| **Took** | How long the API took to answer. |

- The tab shows the newest 50 requests and refreshes itself every 15 seconds. There is no filter or paging; older requests are kept for 7 days but not shown here.
- Only requests made with a valid key are listed. A request with a missing, wrong or revoked key, from a suspended workspace, or over the rate limit is refused before the key is recognised, so it doesn't appear. If your integration gets `401` or `429` and the log shows nothing, that is why.
- `permission_denied` on a `403` usually means the key lacks a scope. The response body names the missing scope. See [Errors](/api/errors).
- Request ids aren't shown in the log. Keep the `request_id` from error responses in your own logs, and quote it if you contact support.

## Quickstart

The **Quickstart** tab has three examples, each in cURL, Node and Python with a copy button:

- **Authentication**: check a key with `GET /ping`.
- **Send an order update on WhatsApp**: a template message with an `Idempotency-Key`.
- **Have an agent call a customer**: an outbound call that captures answers, with a link to the [call outcomes guide](/api/call-outcomes).

![The Quickstart tab with Getting started, a Live environment badge, and cURL examples for checking a key and sending a WhatsApp order update](https://docs.amomic.in/screens/developers/quickstart.light.webp)

The snippets already use your workspace's base URL, and the example phone number is in your workspace's country format. Replace the number and template name with real ones before you run them: they send real messages and place real calls.

The **Endpoints** card lists 14 of the most-used endpoints with the scope each needs, and **OpenAPI schema** opens the machine-readable schema. The full list of endpoints, including contacts, tickets, campaigns and Duesly, is in the [API reference](/api/overview).

## Troubleshooting

| Problem | What to do |
|---|---|
| A Member can't find **Developers** | It is for owners and admins only. Ask an admin, or have an owner change the person's role. |
| You lost a key before copying it | It can't be shown again. **Roll** it, deploy the new key, and let the old one expire. |
| Requests fail with `403` and `permission_denied` | The key lacks a scope. Create a key with the right scopes, deploy it, and revoke the old one. |
| Requests fail with `401` and nothing is in the log | The key is wrong, revoked or expired after a roll. Check the masked prefix against the list. |
| Requests fail with `429` | Over 120 requests a minute for that key. See [Rate limits](/api/rate-limits). |
| **Test** stays `queued` | The endpoint is disabled. **Enable** it, then test again. |
| Deliveries show `no response` | Your server took longer than 10 seconds or couldn't be reached. Answer with `2xx` quickly and do the work afterwards. |
| Deliveries show a `3xx` and stop | Redirects aren't followed or retried. Use the final URL as the endpoint. |
| An endpoint is **Disabled** with a red note | 15 events in a row failed. Fix your server, **Enable**, **Test**, then **Replay** the deliveries it missed. |
| Signatures don't verify | Verify against the raw request body, before any JSON parsing. See [Verifying signatures](/webhooks/signatures). |

## Where to go next

::: cards

::: card Make a request
[Your first API call](/start/first-api-call): from a new key to a sent message.
:::

::: card Pick the right scopes
[Scopes](/api/scopes): what each scope opens, endpoint by endpoint.
:::

::: card Handle events properly
[Getting events](/webhooks/overview) and [Retries and failures](/webhooks/reliability).
:::

:::
