Skip to content

Public Developer API Reference ​

The OIM backend provides a clean, versioned REST API for compiling layout measurements, packaging signed interactive media assets, and retrieving public cryptographic keys.

Base URL: https://api.oim.media


1. Authentication and API Keys ​

EndpointKeyLimit
POST /v1/oim/packageRequired (401 OIM_E_AUTH_REQUIRED without it)30 / minute per IP, plus the monthly signing quota
POST /v1/oim/compileOptional60 / minute per IP
POST /v1/oim/extractNo30 / minute per IP
GET /v1/media/keysNo—

API keys are exclusive to the Enterprise plan; a key from any other plan is rejected with 403. Send the key in a header:

http
X-API-Key: YOUR_DEVELOPER_KEY

or as a bearer token:

http
Authorization: Bearer YOUR_DEVELOPER_KEY

Keep the key on your server

The key signs against your quota. Do not put it in browser code or in an app you distribute, and do not send it in the URL (?api_key=): URLs end up in logs and histories. Call the API from your backend.

Avoid requests that will fail

  • Do not call /package without a key: it always answers 401.
  • Validate before signing: 400 and 403 rejections arrive before any quota is used, but they count towards the per-minute limit.
  • On 429, wait the seconds in Retry-After before retrying; retrying in a loop extends the block.
  • To retry a signature after a network drop, use Idempotency-Key (see below): it is not charged twice.

Rate limits: RateLimit-* and Retry-After ​

Rate-limited endpoints answer with RateLimit-Limit (requests allowed in the window), RateLimit-Remaining (left in this window) and RateLimit-Reset (seconds until the window resets). Past the limit the response is 429 with Retry-After: the seconds to wait before retrying.

Tracing a request: X-Request-ID ​

Every response carries an X-Request-ID header. If something fails, include it when you report the problem: it identifies your request in our logs. You can also send your own X-Request-ID (8 to 128 characters of A-Z, a-z, 0-9, ., _ or -) and the response returns it unchanged; any other value is replaced with a new one.

Security headers ​

Every response carries defensive security headers:

  • Cross-Origin-Resource-Policy: cross-origin
  • Strict-Transport-Security: max-age=63072000; includeSubDomains
  • X-Content-Type-Options: nosniff
  • X-Frame-Options: DENY
  • Referrer-Policy: no-referrer

Request payload limits ​

  • Non-upload JSON endpoints accept payloads up to 5 MB. Chunked transfer encoding is not supported on non-upload endpoints and is rejected with 400 Bad Request.
  • Upload and compile endpoints accept files up to 50 MB (MAX_UPLOAD_SIZE). Base images are capped at 8192 px per side and 16 MP (16,777,216 pixels total).

2. Compile Measurements: POST /v1/oim/compile ​

Converts raw screen pixel coordinates into container-relative adaptive percentages and cqw units.

  • Endpoint: POST /v1/oim/compile
  • Rate Limit: 60 requests / minute
  • Request Body (application/json):
json
{
  "canvas_width": 1080,
  "canvas_height": 1080,
  "slots_raw": [
    {
      "id": "hero_text",
      "type": "text",
      "x_px": 108,
      "y_px": 216,
      "width_px": 864,
      "height_px": 120,
      "content": {
        "en": "Empower your media",
        "es": "Potencia tus medios"
      }
    }
  ]
}
  • Response (200 OK): Returns normalized OimMetadata with coordinates scaled to container query widths.

3. Package & Sign Asset: POST /v1/oim/package ​

Combines a clean baked PNG image (Layer −1) with compiled metadata, signs the payload with ECDSA P-256, and generates the final .oim.png binary.

  • Endpoint: POST /v1/oim/package
  • Authentication: API key required
  • Rate Limit: 30 requests / minute, plus the monthly signing quota
  • Request Format: multipart/form-data
  • Parameters:
    • file: PNG image file binary (baked image, Layer −1). Up to 50 MB, at most 8192 px per side, and at most 16,777,216 pixels (16 MP). Exceeding image bounds returns 400 Bad Request.
    • metadata: Serialized JSON string matching OimMetadataSchema.
bash
curl -X POST https://api.oim.media/v1/oim/package \
  -H "X-API-Key: $OIM_API_KEY" \
  -F "[email protected]" \
  -F "[email protected]" \
  --output result.oim.png
  • Response (200 OK): Binary image/png stream containing the embedded, signed OIM_Data chunk.

  • Account refusals (403, also on /v1/oim/compile): nothing is signed and no quota is used.

    codeMeaning
    OIM_E_POLICIES_PENDINGThe account has new Terms or Privacy Policy already in force and not accepted. Accept them at https://oim.media/#/politicas and retry.

Retrying without paying twice: Idempotency-Key ​

Each signature uses one unit of the monthly quota. If the connection drops after the server signed, a retry would be charged again. To avoid that, send an Idempotency-Key header with a value you generate once per request, a UUID for example, and send the same value when you retry that request.

  • Within 24 hours, a retry with the same key and the same content is signed again without using quota.
  • The same key with different content is refused with 422. Use a new key for every new file.
  • A malformed key, outside 16–128 characters of A-Z a-z 0-9 _ -, is refused with 400.
  • The header is optional: without it, every request is charged as before.
bash
curl -X POST https://api.oim.media/v1/oim/package \
  -H "X-API-Key: $OIM_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -F "[email protected]" \
  -F "[email protected]" \
  --output result.oim.png

A lighter base image: base_optimization ​

The server always stores the base image without an unused transparency channel: an opaque RGBA base becomes RGB, with identical pixels. An optional form field asks for more:

ValueWhat it does
lossless (default)Identical pixels. Only the unused transparency is dropped.
paletteReduces an opaque base to 256 colours. Much smaller (around 60% on large illustrations) but the pixels change: gradients may show slight banding.
  • A base with real transparency is never reduced to a palette: it is stored lossless.
  • The X-OIM-Base-Optimization response header tells which one was applied.
  • Any other value is refused with 400 and the code OIM_E_BASE_OPTIMIZATION_INVALID, before any quota is used.

Text marks ​

A text whose mark tags are malformed (an unknown mark, an unclosed or nested tag, a single brace that is not a tag; see Text marks in the format specification) is refused with 400 and the code OIM_E_TEXT_MARKS_INVALID, naming the layer and the language, before any quota is used. A signed .oim therefore only carries well-formed texts.

  • With Idempotency-Key, the option is part of the content: the same key with another option is refused with 422.
bash
curl -X POST https://api.oim.media/v1/oim/package \
  -H "X-API-Key: $OIM_API_KEY" \
  -F "[email protected]" \
  -F "[email protected]" \
  -F "base_optimization=palette" \
  --output result.oim.png

4. Extract Metadata: POST /v1/oim/extract ​

Reads and validates an existing .oim.png asset, extracting both the uncompressed metadata JSON and the clean baked base image (Layer −1).

  • Endpoint: POST /v1/oim/extract

  • Request Format: multipart/form-data

  • Parameters:

    • file: Uploaded .oim.png binary (PNG only, up to 50 MB).
  • Rate Limit: 30 requests / minute

  • Response (200 OK):

json
{
  "image_base64": "iVBORw0KGgo...",
  "metadata": { "version": "1.27.2", "signature": "MEQCIF+...", "slots": [] },
  "revoked": false
}

metadata holds the file's JSON as is, or { "error": ..., "slots": [] } when the PNG carries no OIM data. revoked is true when the file has been revoked.


5. Public Cryptographic Keys: GET /v1/media/keys ​

Exposes active and historical public verification keys in standard JSON Web Key (JWK) format.

  • Endpoint: GET /v1/media/keys
  • Authentication: Public (no key required)
  • Response (200 OK):
json
{
  "keys": [
    {
      "kty": "EC",
      "crv": "P-256",
      "x": "f83OJ3D2xFmT4v7Z2V4s8uY9xQ7...",
      "y": "x_da7W8mP2zQ9v4L1m3s8uY9xQ7...",
      "kid": "v1",
      "use": "sig"
    }
  ]
}

Client players and independent auditors use these JWK keys to mathematically verify signature validity without connecting to private infrastructure.