Skip to content

Developers

AI Gateway API

The Al-Maqdisi AI Gateway is a secure proxy between client applications and the Gemini API. Apps never hold a provider key — they name a pre-approved task, and the gateway applies the model, limits, and safety settings server-side.

Base URL https://api.almaqdisiproductions.com

Overview

Embedding an AI provider key inside a mobile app makes it publicly extractable — keys shipped in binaries are routinely harvested and abused. The gateway removes the key from the client entirely: the app sends a task name and a message, and the gateway holds the provider key encrypted server-side, enforces a per-app task allowlist, applies rate limits, and streams the model's answer back.

  • Task allowlist — a client can only name a task. The model, output cap, streaming/JSON permission, temperature ceiling, and safety settings are decided server-side per task. Capabilities outside the allowlist (e.g. image generation, arbitrary model selection) do not exist on this API surface.
  • Two auth modes per apppublic for mobile clients (app id only; nothing secret ships in the binary) and token for server-to-server callers (a revocable bearer token kept in server secrets).
  • Operator controls — keys, tasks, tokens, rate limits, and a per-app kill switch are managed at runtime in a private portal; no client release is needed to rotate a key or pause traffic.

Authentication

Every request carries X-App-Id. Whether a bearer token is also required depends on the app's operator-configured auth mode:

Mode Required headers Intended callers
public X-App-Id only Mobile apps — nothing secret is provisioned at build time; protection comes from the task allowlist, rate limits, and the operator kill switch
token X-App-Id + Authorization: Bearer <app token> Server-to-server callers whose token stays a true secret (backend env / secrets manager)

POST /v1/invoke

The single proxy endpoint. Send a task name and a message; receive the model's answer as JSON or as a Server-Sent-Events stream.

Request headers

# public mode
X-App-Id: your-app-id
Content-Type: application/json

# token mode
X-App-Id: your-app-id
Authorization: Bearer amp_your-app-id_XXXXXXXX
Content-Type: application/json

Request body

Field Type Required Notes
task string Yes Names an allowlisted task (e.g. chat). The server decides the model, output caps, and safety settings for it — the client cannot override them.
message string Yes The user message. Clamped server-side to the task's input limit.
systemInstruction string No System prompt; accepted only if the task permits one.
history array No Prior turns as { role: "user" | "agent", text }. Only the most recent turns within the task's limit are kept.
generationConfig object No temperature, maxOutputTokens, topP, responseMimeType — every field is clamped to the task's server-side ceilings.
stream boolean No Request an SSE stream. Honored only if the task allows streaming.
clientId string No A stable anonymous identifier (e.g. an install UUID) used for fair per-client rate limiting. Falls back to IP when absent.

Example request

{
  "task": "chat",
  "message": "Summarize this in one sentence: …",
  "history": [
    { "role": "user",  "text": "…" },
    { "role": "agent", "text": "…" }
  ],
  "generationConfig": { "temperature": 0.3, "maxOutputTokens": 1024 },
  "stream": false,
  "clientId": "6f1c9c1e-anon-install-uuid"
}

Response — single-shot

{
  "text": "…the model's answer…",
  "usage": { "promptTokens": 132, "outputTokens": 456 }
}

Streaming

With "stream": true (on tasks that allow it) the response is text/event-stream. Each frame is a JSON object:

data: {"token":"The "}
data: {"token":"answer "}
data: {"token":"continues…"}
data: {"done":true}

# on a mid-stream failure the gateway emits one error frame, then closes:
data: {"error":"upstream_error"}

Concatenate token values in order; treat done as end-of-message; surface error frames through your app's normal degraded-state handling.

GET /v1/health

Unauthenticated liveness probe.

{ "ok": true, "service": "almaqdisi-ai-gateway", "ts": "2026-07-18T12:00:00.000Z" }

Errors

Every non-2xx response uses one standardized envelope. Branch on code, never on message:

{ "error": { "code": "rate_limited", "message": "Rate limit exceeded. Retry later." } }
Code HTTP Meaning
bad_request 400 Malformed body / missing required field
message_required 400 message empty after trimming
unknown_task 400 Task not registered for this app (the allowlist said no)
stream_not_allowed 400 stream: true on a task that does not permit streaming
unauthenticated 401 Missing bearer token or X-App-Id
invalid_token 401 Token unknown, revoked, or wrong for this app
task_disabled 403 Task exists but is currently switched off
safety_blocked 422 The AI provider refused the content
rate_limited 429 Per-client or per-app window exhausted (Retry-After header set)
upstream_error 502 The AI provider returned an error (also surfaces provider 429s)
app_disabled 503 The app's proxy is paused by the operator
no_active_key 503 No active provider key is configured for this app
internal 500 Gateway error

Rate limits

Two fixed windows are checked on every request, and both must pass:

  • Per client — each task has a per-minute allowance, bucketed by clientId (or IP when absent). Send a stable anonymous clientId so one heavy user cannot exhaust the shared IP bucket.
  • Per app — a global per-minute ceiling across all of an app's clients.

A 429 response includes a Retry-After header (seconds). Back off and retry after that interval.

Code examples

Mobile app — public mode (zero build-time credentials)

const res = await fetch('https://api.almaqdisiproductions.com/v1/invoke', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-App-Id': 'your-app-id', // the only identity the build carries
  },
  body: JSON.stringify({ task: 'chat', message, history, stream: true }),
});

Server-to-server — token mode

const res = await fetch(`${process.env.AI_GATEWAY_URL}/v1/invoke`, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: `Bearer ${process.env.AI_GATEWAY_APP_TOKEN}`,
    'X-App-Id': 'your-app-id',
  },
  body: JSON.stringify({ task: 'ragAnswer', message: combinedPrompt }),
});
const { text } = await res.json();

Getting access

Apps are onboarded by the gateway operator through a private management portal — registration, task allowlists, provider keys, tokens, and traffic insight are all managed there. The gateway currently serves Al-Maqdisi Productions apps; if you are building with us or want the same architecture for your own apps, get in touch.

Building your own? The full architecture and an end-to-end implementation guide are documented in our open playbook, API-Key-Gateway-Proxy-Architecture.