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

# Setting up endpoints

> Register an HTTPS endpoint with a workspace API key, activate it by echoing the test challenge, and pause, update or remove it when your receiver changes.

An endpoint is the HTTPS URL Base44 sends your events to. You can register one in your workspace settings, or with a workspace API key when a script sets up your workspace. This page covers the API. For the settings page, see [Sending workspace events with webhooks](https://docs.base44.com/Enterprise/workspace-webhooks.md).

> [!WARNING]
>
> Outbound webhooks are available on the Business and Enterprise plans.

***

## Authenticating

Endpoint requests use a workspace API key with the `outbound_webhooks:write` scope, shown as **Manage outbound webhooks** when you create the key. Send it in the `Authorization` header. The key decides the workspace, so no workspace ID appears in the URL.

```bash theme={null}
Authorization: Bearer YOUR_API_KEY
```

To create a key, see [Managing workspace secrets](https://docs.base44.com/Enterprise/workspace-secrets.md). Only workspace owners and admins can create one.

> [!WARNING]
>
> Treat the key like a password. Anyone who holds it can send your workspace's events to a URL of their choice.

***

## Registering an endpoint

Registering creates the endpoint and activates it in the same call. Base44 sends a signed `webhook.test.v1` event to your URL, and the endpoint becomes **Active** only if your receiver answers with a 2xx within 5 seconds and echoes the challenge.

```bash theme={null}
curl --request POST \
  --url https://app.base44.com/api/v1/outbound-webhooks/endpoints \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
    "target_url": "https://hooks.yourcompany.com/base44",
    "selected_event_types": ["app.created.v1", "app.published.v1"],
    "description": "Production sync"
  }'
```

The URL must use `https`, resolve to a public address (not localhost or a private network), and can't include a username or password. `selected_event_types` takes at least 1 event type, and `description` is optional, up to 200 characters. Unknown fields are rejected. Base44 never follows redirects, so register the exact URL that answers.

The response is `201` whether or not activation succeeded, because the endpoint was created either way. Check `activated`:

```json theme={null}
{
  "endpoint": {
    "id": "68d4e5f6a7b8c9d0e1f2a3b4",
    "target_url": "https://hooks.yourcompany.com/base44",
    "description": "Production sync",
    "selected_event_types": ["app.created.v1", "app.published.v1"],
    "state": "pending",
    "health": "unknown",
    "consecutive_failed_deliveries": 0
  },
  "activated": false,
  "http_status": 200,
  "failure_category": "client_error",
  "detail": "The receiver answered 2xx but did not echo the challenge from the request body. Return the `challenge` value to confirm you received it."
}
```

When `activated` is `false`, fix your receiver and run the test again. Don't register the endpoint a second time.

### Echoing the challenge

The echo proves you control the URL. Without it, anyone could point Base44's traffic at a host that never asked for it.

The test event's `data.challenge` holds a one-time value. Return it in the response body in either of these forms:

```json theme={null}
{ "challenge": "8f14e45fceea167a5a36dedd4bea2543" }
```

Or the value alone, as the whole body. Anything else fails, including a partial match.

A simple receiver checks the event type before its normal handling:

```js theme={null}
// after verifying the signature and parsing the body
if (event.type === "webhook.test.v1") {
  return Response.json({ challenge: event.data.challenge });
}
```

> [!TIP]
>
> Verify the signature on the test event too. It's signed exactly like a real delivery, so a receiver that passes the test has proven it can verify production traffic.

***

## Testing an endpoint again

Run the activation test again after you fix your receiver, or after you change the endpoint's URL.

```bash theme={null}
curl --request POST \
  --url https://app.base44.com/api/v1/outbound-webhooks/endpoints/{endpoint_id}/test \
  --header 'Authorization: Bearer YOUR_API_KEY'
```

The response has the same shape as registration. The test only runs on a pending or active endpoint. To bring back a paused endpoint, resume it instead.

***

## Managing endpoints

These requests use the same header as registration. Get, update and pause return the endpoint. Resume returns the same shape as registration. Delete returns the endpoint's `id` and `deleted: true`.

| Request | What it does |
| - | - |
| `GET /api/v1/outbound-webhooks/endpoints` | Lists your endpoints, oldest first. Pass the returned `next_cursor` as `cursor` to get the next page. |
| `GET /api/v1/outbound-webhooks/endpoints/{endpoint_id}` | Gets one endpoint. |
| `PATCH /api/v1/outbound-webhooks/endpoints/{endpoint_id}` | Changes `target_url`, `selected_event_types` or `description`. |
| `POST /api/v1/outbound-webhooks/endpoints/{endpoint_id}/pause` | Stops deliveries, for example while you redeploy your receiver. |
| `POST /api/v1/outbound-webhooks/endpoints/{endpoint_id}/resume` | Starts deliveries again. |
| `DELETE /api/v1/outbound-webhooks/endpoints/{endpoint_id}` | Removes the endpoint. Events not yet delivered to it aren't sent. |

For every request and response field, see the [API reference](https://docs.base44.com/api-reference/outbound-webhooks/register-an-endpoint.md).

> [!NOTE]
>
> **What changes an endpoint's state:**
>
> * Changing `target_url` returns the endpoint to **Pending**. Run the test again to activate the new URL.
> * Changing the selected events or the description doesn't change its state.
> * Events that happen while an endpoint is paused or pending aren't sent to it, even after it's active again.
> * Resuming an endpoint that Base44 auto-paused returns it to **Pending**. Run the test to activate it again. See [Delivery and retries](https://docs.base44.com/developers/references/outbound-webhooks/get-started/delivery-and-retries.md).

***

## Errors and rate limits

Errors use one shape, with a stable `code` to match on:

```json theme={null}
{
  "error": {
    "code": "invalid_request",
    "message": "Remove the credentials from the webhook URL. Deliveries are authenticated with a signature your receiver verifies, so a user:password@ prefix is not needed and would be stored in audit logs.",
    "details": { "reason": "target_url_has_credentials" }
  }
}
```

| Status | `code` | Meaning |
| - | - | - |
| 400 | `invalid_request` | A field is missing or invalid. `details.reason` or `details.fields` says which. |
| 401 | `unauthenticated` | The key is missing or not a workspace API key. |
| 403 | `permission_denied` | The key doesn't have the `outbound_webhooks:write` scope, or your plan doesn't include outbound webhooks. |
| 404 | `not_found` | No endpoint with that ID in your workspace. |
| 409 | `limit_exceeded` | Your workspace already has 10 endpoints. |
| 409 | `conflict` | The endpoint changed while the request ran. Get it again and retry. |
| 429 | `rate_limited` | Too many requests. Wait for the time in `Retry-After`. |
| 500 | `internal_error` | Something went wrong on our side. Retry with exponential backoff. |

Each workspace can make at least 300 endpoint reads, 60 endpoint changes and 10 activation tests per minute.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.