Mite developer docs
SDK, REST API, authentication, errors, rate limits, 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
- Create an app in the Mite dashboard and generate
an API key under Settings → Keys. - Install the SDK in your Expo or React Native app.
- Submit your first bug report.
npm install @usemite/mite-sdk
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. 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.
Submit a bug report
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" }
}'
{ "id": "j57...", "status": "NEEDS_TRIAGE" }
Errors
Every failure returns JSON, never HTML. Branch on code, not on error.
{
"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 over one minute. They are
scoped to the key rather than to the application, so one misbehaving key cannot
exhaust the budget of a sibling key on the same app.
| Endpoint | Policy | Requests per minute |
|---|---|---|
/api/v1/bug-reports |
bug-reports |
60 |
/api/v1/upload-url |
upload-url |
30 |
/api/v1/identify |
identify |
120 |
/api/v1/releases |
releases |
120 |
/api/v1/announcements |
announcements |
120 |
/api/v1/feature-requests (GET) |
feature-requests-list |
120 |
/api/v1/feature-requests (POST) |
feature-requests-create |
30 |
/api/v1/feature-requests/vote |
feature-requests-vote |
60 |
/api/v1/feature-requests/votes |
feature-requests-votes |
120 |
/getImage |
images |
300 |
/api/v1/health is unauthenticated and unmetered.
Rate limit headers
Every metered response carries your remaining quota, so you can throttle before
you are refused rather than discovering the limit by hitting it. The fields
follow the IETF RateLimit header fields draft.
RateLimit-Policy: "releases";q=120;w=60
RateLimit: "releases";r=118;t=1
RateLimit-Limit: 120
RateLimit-Remaining: 118
RateLimit-Reset: 1
| Field | Meaning |
|---|---|
RateLimit-Policy |
The quota in force: q requests per w seconds |
RateLimit |
What is left for you: r requests, t seconds until the quota is whole |
RateLimit-Limit |
Superseded plain-integer form of q |
RateLimit-Remaining |
Superseded plain-integer form of r |
RateLimit-Reset |
Superseded plain-integer form of t |
The three plain-integer fields are from an earlier draft and are no longer part
of the specification. Mite still sends them because most deployed HTTP clients
read them; prefer RateLimit and RateLimit-Policy in new code.
All of them are named in Access-Control-Expose-Headers, so a browser can read
them cross-origin.
A refused request returns 429 with Retry-After in seconds, alongsideRateLimit reporting r=0. When both are present, Retry-After is
authoritative.
HTTP/1.1 429 Too Many Requests
Retry-After: 1
RateLimit-Policy: "bug-reports";q=60;w=60
RateLimit: "bug-reports";r=0;t=60
Rate limits on usemite.com
The machine-readable documents on usemite.com carry RateLimit-Policy and are
metered per client at 600 requests per minute. Those documents are/openapi.json, /api/v1, /.well-known/api-catalog, /agents.md,/llms-full.txt, and the JSON errors under /api/.
Those responses carry no live RateLimit field. They are publicly cacheable,
and a shared cache would otherwise hand one client's remaining quota to the
next. A refusal is no-store, so it carries the full set.
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 | OpenAPI 3.1 description of the Mite API |
| /api/v1 | Mite API discovery document |
| /.well-known/api-catalog | Mite API catalog, as an RFC 9727 linkset |
| /agents.md | When to use Mite, and how to make the first call |
| /llms.txt | Index of Mite's pages for agents |
| /llms-full.txt | Every Mite page as one Markdown document |
| /sitemap.xml | Every public page |
| /docs.md | This page as Markdown |
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
for SDK problems, or use the in-app feedback widget in the Mite dashboard.