> ## Documentation Index
> Fetch the complete documentation index at: https://orwel-22af1265.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Troubleshooting

> Partial batches (HTTP 207), rejected or unknown event codes, and conversions that fail.

<Tip>
  The fastest way to debug an install is to send traffic with the [development key](/guides/dev-mode) and open **Dev mode**: every request shows up live with the reason it failed and how to fix it. Add `debug: true` to `orwel.init()` to see the SDK logs in the browser console.
</Tip>

## How the ingest answers

| Endpoint | Status | Meaning |
| - | - | - |
| `POST /ingest` | `200` | The event was stored. |
| `POST /ingest` | `400` | The event was rejected. The body says why, for example `Event not found: <code>`. |
| `POST /ingest/batch` | `200` | Every event in the batch was stored. |
| `POST /ingest/batch` | `207` | Some events were stored and some were not. The refused events are in `failedEvents`. |
| `POST /ingest/batch` | `400` | The batch itself is invalid: bad JSON, missing `batchId`, `count` or `events`, `count` not equal to the number of events, more than 100 events, or a bad key. Nothing was stored. |
| `POST /ingest/batch` | `500` | No event in the batch could be stored. |

A `207` body looks like this:

```json theme={null}
{
  "success": false,
  "error": "Some events failed to process",
  "code": "VALIDATION_ERROR",
  "details": {
    "processed": 9,
    "failed": 1,
    "batchId": "batch_1760000000000_k2j3h4",
    "failedEvents": [ { "type": "track", "code": "quote_sent", "...": "..." } ]
  }
}
```

The SDK does not retry rejected events, because resending an invalid event would loop forever. Since SDK 1.7.1 a `400` is logged in the console with the server response and the rejected codes before the events are discarded:

```text theme={null}
Batch rejected (400) - events DISCARDED, not retrying  { codes: [...], serverResponse: "..." }
Event rejected (400) - DISCARDED, not retrying          { code: "...", serverResponse: "..." }
```

A `207` counts as delivered for the SDK, so the events it refused are not logged in the console. Use Dev mode to see them.

## Events rejected as unknown

**Symptom:** some `track()` calls never appear, the batch answers `207` (or `500` if every event failed), and Dev mode shows `event_not_found`.

**Cause:** the server only accepts `track()` codes that exist in your workspace catalog: the Orwel catalog plus the custom codes your workspace registered. Codes are not created on the fly.

**Fix:**

1. Open **Journeys setup** or **Features setup** in the Development section, add the code to a journey or feature (from the catalog, or as a **Custom event**) and save. See [Journeys and features setup](/guides/journeys-and-features).
2. Or change your code to an existing catalog code.
3. Check the **Status** tab: the code should move from "Not registered" to "Tested" once it arrives with the development key.

Conversions are not gated by the catalog, so this never affects `conversion()`.

## Events lost on large flushes (SDK before 1.7.1)

**Symptom:** pages that fire many events (long sessions, heavy auto detection) lose whole blocks of events, with nothing in the console and nothing on the server.

**Cause:** before 1.7.1 the SDK posted the whole queue (up to 1000 events) in one batch. The server caps a batch at 100 events and answers `400`, and older SDKs treated that `400` as "do not retry" without logging anything.

**Fix:** update the SDK. 1.7.1 sends the queue in chunks of 100.

```bash theme={null}
npm i orwel@latest
```

## A conversion fails or never shows up

`conversion()` is async and resolves with the real outcome. Read it:

```ts theme={null}
const { success, reason } = await orwel.conversion('demo_request', { email })
if (!success) console.warn('Orwel conversion failed:', reason)
```

| `reason` | What happened | Fix |
| - | - | - |
| `visitor_unresolved` | The visitor id did not resolve within 5 seconds, so the conversion was not sent (it would have arrived with no visitor). | Make sure `orwel.init()` runs early on every page, before the form can be submitted, and that requests to `api.orwel.io` are not blocked (ad blockers, a strict Content Security Policy). |
| `delivery_failed` | The request was sent but the server did not acknowledge it (network error, timeout, or a rejection). | Check the console with `debug: true` and the request in Dev mode. |
| `error` | Something threw inside the SDK. | Check the console with `debug: true`. |

If `conversion()` throws instead of resolving, the input is invalid: the code is not snake\_case, the properties are not an object, or an email field is not a valid address.

### The conversion arrives but the lead looks wrong

| Symptom | Cause | Fix |
| - | - | - |
| No notification email, lead not enriched | No email (or phone) in the conversion properties or a previous `identify()`. | Pass `email` in the conversion properties. |
| The lead shows as direct or organic | The landing URL had no UTMs or ad click ids. | Tag your ads and links (see [Attribution](/sdk/attribution)). Test with `?utm_source=test`. |
| Two leads for one submit | SDK before 1.6 had no `conversionId`, so retries were not deduplicated exactly. | Update the SDK. |
| The conversion is missing after a successful submit and a `form_abandon` appears instead | The form was unmounted before the conversion was sent, or `orwel.form()` with `trackAbandon` saw the form disappear. | `await orwel.conversion()` before showing the success state, and do not combine `orwel.form()` with a manual conversion on the same form. |
| The lead has a **Dev** badge and no integrations ran | It was sent with the development key. | Expected. Use the production API key in production. |

## `init()` throws

* `apiKey must start with "orwel_"` or `appears to be invalid (too short)`: the environment variable is empty or wrong. Check the variable name for your framework (for example `NEXT_PUBLIC_ORWEL_KEY`, `PUBLIC_ORWEL_KEY`, `VITE_ORWEL_KEY`).
* `config must be an object`: call `orwel.init({ apiKey })`, not `orwel.init(apiKey)`.

## API and MCP

* `401` with a public or development key: those keys only send data. Create an [API key](/authentication) (`orwel_sk_`) to read.
* `403` from a browser: the page's origin is not in the key's allowed origins, or the key is server only.
* `403 plan_not_allowed` on `/mcp`: the workspace has no active subscription.


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