MIRA FIVE

Overview

Send events and read feature flags over plain HTTP, from curl or any language, without an SDK.

The ingest API is the HTTP interface every MIRA FIVE SDK speaks: it takes batches of events and serves feature-flag documents. Call it directly when there is no SDK for your language, when you write an SDK, or to test a key from a terminal. For JavaScript and PHP, an SDK does all of this for you.

Base URL

https://events.mirafive.io

Every path starts with /v1. Bodies are UTF-8 JSON. No endpoint sets or reads cookies.

Every /v1 path answers CORS for any origin: Access-Control-Allow-Origin: *, methods GET, POST and OPTIONS, request headers Authorization and Content-Type, Retry-After exposed, no credentials, preflights cached for 86,400 seconds. Which sites may use a website key is checked separately, against the source's allowed origins (see Website key in the path).

Authenticate

A source has exactly one kind of key, and the kind decides where the key travels. See Keys for where to create them.

KeySourceWhere it goesWho sends it
Website keywebsite sourcethe URL pathbrowsers, and any client whose code is public
Secret keyserver sourceAuthorization: Bearer mf_…servers only

Keys look like mf_ab12cd34_…: mf_, eight lower-case letters or digits, _, then the secret part (mf_[a-z0-9]{8}_[A-Za-z0-9_-]+). Older keys of the form mira_ik_… are still accepted. A missing, unknown, revoked or archived key gets one answer: 401 unauthorized.

Website key in the path

Browsers send the website key in the path and the JSON body as Content-Type: text/plain;charset=UTF-8:

POST https://events.mirafive.io/v1/batch/mf_…

That makes the request a CORS simple request: there is no preflight, and it works with navigator.sendBeacon() and fetch(…, { keepalive: true }). The server reads the body as JSON whatever the content type says.

When a request carries an Origin header, the origin must be one of the source's allowed origins, or the answer is 403 origin_not_allowed. An apex domain and its www. twin count as one site (same scheme and port). localhost and 127.0.0.1 pass on any port. A source with no allowed origins accepts every origin, and a request without an Origin header (curl, a server) is not checked.

Secret key as a bearer

Servers send the secret key in the Authorization header and the body as Content-Type: application/json:

POST https://events.mirafive.io/v1/batch
Authorization: Bearer mf_…

The scheme name is case-insensitive (bearer works too).

Never ship a secret key to a browser. A secret key that arrives with an Origin or Sec-Fetch-Site header is marked exposed: events are still accepted, but the flag endpoints refuse it with 403 secret_key_exposed until you rotate it.

Swapped keys are refused: a website key sent as a bearer gets 403 website_key_as_bearer, a secret key in a path gets 403 secret_key_in_path. See Exposed secret keys.

Endpoints

Method and pathKeyDoes
POST /v1/batchsecret key, bearerStores a batch of events from a server. Send events
POST /v1/batch/{websiteKey}website key, pathStores a batch of events from a browser. Send events
GET /v1/flags/{websiteKey}website key, pathReturns the browser (or values) flag document. Feature flags
POST /v1/flags/{websiteKey}website key, pathReturns the browser flag document with the browser's segment membership. Feature flags
GET /v1/flagssecret key, bearerReturns the server flag document, with an ETag. Feature flags
POST /v1/flags/segmentssecret key, bearerReturns segment membership for up to 100 users or browsers. Feature flags

A path whose key segment does not look like a key answers 404.

Check a key

Send a batch with one $install_check event. It proves the key and the host work, and is never stored or billed:

curl -i https://events.mirafive.io/v1/batch \
  -H "Authorization: Bearer $MIRAFIVE_SECRET_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"v":1,"batch":"0192d4a8-7b1c-4e8a-9c1d-2b3e4f5a6b7c","mode":"consentless","events":[{"name":"$install_check"}]}'
202 Accepted
{ "batch": "0192d4a8-7b1c-4e8a-9c1d-2b3e4f5a6b7c", "accepted": 0, "dropped": 1, "reason": "install_check" }

For a website key, send the same body to /v1/batch/$MIRAFIVE_WEBSITE_KEY without the Authorization header. A 401 means the key is wrong or revoked; "reason": "ingestion_paused" means the key works but the organization is paused.

Limits

LimitValueOver it
Batch body1 MiB (1,048,576 bytes)413 payload_too_large
Events per batch1 to 1,000400 validation_failed
Properties per event32,768 bytes as UTF-8 JSON, 64 leaf values, 5 levels, keys up to 128 characters400 validation_failed
Segment lookup body (POST /v1/flags/{websiteKey})1,024 bytesmembership left out
Units per segment lookup (POST /v1/flags/segments)100422 too_many_units
Requests and events per second or minuteper address, per key429 rate_limited with Retry-After

Field limits are on Send events, rate limits on Errors and retries.

Versioning

This is version 1 of the protocol, in the path (/v1) and in the bodies:

  • A batch MUST carry "v": 1. Any other value is 400 validation_failed.
  • Flag documents carry "v": 1. Treat a document with any other version as unreadable and keep the last one you had.
  • The server ignores fields in a batch that it does not know, so an SDK can add hints without breaking older servers. Do not use that to send data the protocol does not define.
  • Ignore unknown fields at every level of an answer. New fields, new reason values and new error codes may appear within v1. Decide retries by status code, never by error code.

When to use an SDK instead

The SDKs implement everything on these pages: batching, retries with the same batch id, consent and collection modes, URL cleaning, flag evaluation, bootstrap blocks and deduplicated exposures. Use one when your stack has it:

Use the ingest API directly for other languages, for a one-off import, or to debug what an SDK sends.

On this page