# Mite developer docs — SDK, REST API, and webhooks

Mite is in-app feedback and release notes for Expo and React Native apps. Your
app sends bug reports, feature requests, and user identities to the Mite API;
you triage them in the Mite dashboard and publish release notes back to the
same app.

This page is the developer index: SDK, REST API, authentication, errors, rate
limits, webhooks, and the machine-readable files that describe all of it.

## Quickstart

1. Create an app in the [Mite dashboard](https://usemite.com/apps) and generate
   an API key under **Settings → Keys**.
2. Install the SDK in your Expo or React Native app.
3. Submit your first bug report.

```bash
npm install @usemite/mite-sdk
```

```tsx
import { Mite, MiteProvider, useBugReport } from '@usemite/mite-sdk'

const mite = new Mite({ apiKey: 'mite_ak_...' })
mite.init()

// Wrap your app once:
<MiteProvider miteInstance={mite}>{/* Your app */}</MiteProvider>

// Then submit bugs from anywhere:
const { submitBugReport } = useBugReport()
await submitBugReport({
  title: 'Something broke',
  description: 'What the user saw',
})
```

## SDK

The React Native and Expo SDK is published as
[`@usemite/mite-sdk`](https://github.com/usemite/mite-sdk). It wraps every
endpoint below, collects device and app context, and retries safely. Use it
unless you have a reason to call the API directly.

## Authentication

Every endpoint except `/api/v1/health` needs a Mite API key, sent as a bearer
token:

```
Authorization: Bearer mite_ak_...
```

Mite API keys are publishable, SDK-style tokens, like a Sentry DSN or a PostHog
project key. They ship inside your mobile binary and anyone can extract them
from a shipped APK or IPA, so **they are not secrets**. Mite handles abuse with
per-key rate limits and instant revocation instead of secrecy. Never use a Mite
key as a substitute for your own user authentication.

Each key carries scopes:

| Scope   | Grants                                                  |
| ------- | ------------------------------------------------------- |
| `read`  | List releases, announcements, feature requests          |
| `write` | Submit bug reports, feature requests, votes, identities |

A request with the wrong scope is refused with `403`.

## Base URL

```
https://intent-okapi-412.convex.site
```

## API endpoints

| Method | Path                             | Scope   | Purpose                                   |
| ------ | -------------------------------- | ------- | ----------------------------------------- |
| `GET`  | `/api/v1/health`                 | none    | Liveness probe                            |
| `POST` | `/api/v1/bug-reports`            | `write` | Submit a bug report                       |
| `POST` | `/api/v1/upload-url`             | `write` | Create a single-use attachment upload URL |
| `POST` | `/api/v1/identify`               | `write` | Create or update an end-user profile      |
| `GET`  | `/api/v1/releases`               | `read`  | List published releases                   |
| `GET`  | `/api/v1/announcements`          | `read`  | List active announcements                 |
| `GET`  | `/api/v1/feature-requests`       | `read`  | List feature requests                     |
| `POST` | `/api/v1/feature-requests`       | `write` | Submit a feature request                  |
| `POST` | `/api/v1/feature-requests/vote`  | `write` | Toggle a vote                             |
| `GET`  | `/api/v1/feature-requests/votes` | `read`  | List one voter's votes                    |
| `GET`  | `/getImage`                      | `read`  | Fetch a stored attachment                 |

Every path also answers `OPTIONS` for CORS preflight.

The full request and response schema for each endpoint is published as OpenAPI
3.1 at [usemite.com/openapi.json](https://usemite.com/openapi.json).

### Submit a bug report

```bash
curl -X POST https://intent-okapi-412.convex.site/api/v1/bug-reports \
  -H "Authorization: Bearer mite_ak_..." \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Crash when opening the Profile tab",
    "description": "The app closes immediately after tapping Profile.",
    "app_version": "1.4.2",
    "device_info": { "model": "iPhone 15", "os": "iOS 18.2" }
  }'
```

```json
{ "id": "j57...", "status": "NEEDS_TRIAGE" }
```

## Errors

Every failure returns JSON, never HTML. Branch on `code`, not on `error`.

```json
{
  "error": "API key is missing the required 'write' scope",
  "code": "forbidden",
  "hint": "Create a key with the write scope in Settings → Keys, or use an existing key that has it."
}
```

| Status | `code`                   | Meaning                                        |
| ------ | ------------------------ | ---------------------------------------------- |
| `400`  | `invalid_request`        | Malformed JSON, or a field failed validation   |
| `401`  | `unauthorized`           | Missing, malformed, or unknown API key         |
| `402`  | `REPORT_QUOTA_EXCEEDED`  | The plan's monthly report allowance is used up |
| `402`  | `STORAGE_QUOTA_EXCEEDED` | The plan's attachment storage is used up       |
| `403`  | `forbidden`              | The key lacks the scope the endpoint needs     |
| `404`  | `not_found`              | No such resource for this application          |
| `413`  | `payload_too_large`      | The request body is larger than 256 KB         |
| `429`  | `rate_limited`           | Per-key rate limit exceeded                    |
| `500`  | `internal_error`         | Unexpected server error                        |

A quota refusal is `402`, never `429`. A `429` tells a client to retry; a
monthly quota cannot improve by retrying, only by changing plan. Quota
responses carry a `quota` object with `limit`, `used`, and `resets_at`.

## Rate limits

Limits are per API key, as a token bucket refilled every minute.

| Endpoint                          | Requests per minute |
| --------------------------------- | ------------------- |
| `/api/v1/bug-reports`             | 60                  |
| `/api/v1/upload-url`              | 30                  |
| `/api/v1/identify`                | 120                 |
| `/api/v1/releases`                | 120                 |
| `/api/v1/announcements`           | 120                 |
| `/api/v1/feature-requests` (GET)  | 120                 |
| `/api/v1/feature-requests` (POST) | 30                  |
| `/api/v1/feature-requests/vote`   | 60                  |
| `/api/v1/feature-requests/votes`  | 120                 |
| `/getImage`                       | 300                 |

A refused request returns `429` with a `Retry-After` header in seconds.

## Webhooks

Mite posts outgoing notifications to Discord and Slack. Add an incoming webhook
URL under **Settings → Webhooks** in the dashboard and choose which events fire:

- a new bug report arrives
- a bug report changes status
- a new feature request arrives

Discord URLs must start with `https://discord.com/api/webhooks/` and Slack URLs
with `https://hooks.slack.com/services/`. Mite does not accept inbound webhooks.

## Machine-readable resources

| Resource                                   | What it is                         |
| ------------------------------------------ | ---------------------------------- |
| [/openapi.json](https://usemite.com/openapi.json) | OpenAPI 3.1 description of the API |
| [/llms.txt](https://usemite.com/llms.txt)         | Index of Mite's pages for agents   |
| [/sitemap.xml](https://usemite.com/sitemap.xml)   | Every public page                  |
| [/docs.md](https://usemite.com/docs.md)           | This page as Markdown              |
| [/api/v1](https://usemite.com/api/v1)             | API discovery document             |

Every public page also answers `Accept: text/markdown` with a Markdown
rendition of itself, and advertises it with a `Link: rel="alternate"` header.

## Support

Open an issue on [github.com/usemite/mite-sdk](https://github.com/usemite/mite-sdk)
for SDK problems, or use the in-app feedback widget in the Mite dashboard.

---

Canonical HTML: https://usemite.com/docs
Site index for agents: https://usemite.com/llms.txt
API description: https://usemite.com/openapi.json
