AeroModel

Documentation

API key safety — do not expose it

The API key generates images without watermark. If it leaks, anyone can consume your quota.

Bad practices (DO NOT DO)

❌ Hard-coded key in HTML

<!-- VISIBLE TO EVERYONE -->
<img src="https://api.aeromodel.dash-systems.fr/v1/images/plane?plane=A320&api-key=sk_live_abcd1234" />

❌ Key in JavaScript bundle

// COMPILED INTO THE PUBLIC BUNDLE, VISIBLE IN F12
const KEY = "sk_live_abcd1234";
fetch(`/v1/images/plane?plane=A320`, { headers: { "x-api-key": KEY } });

❌ Key in a client-exposed env variable

# Next.js — ALL NEXT_PUBLIC_* vars are exposed to the browser
NEXT_PUBLIC_AEROMODEL_KEY=sk_live_abcd1234   # ❌
# Vite — all VITE_* vars are exposed
VITE_AEROMODEL_KEY=sk_live_abcd1234   # ❌

❌ Key committed to git

Even in a private repo, consider the key compromised once it's in git. Rotate it immediately.

Good practices

✅ Pattern 1: display the image directly

If you only want to display an image on a public web page, don't use a key:

<img src="https://api.aeromodel.dash-systems.fr/v1/images/plane?plane=A320&airline=AF" />

The image is served with a watermark (transparent Aeromodel logo). This is the intended mode for free public use.

✅ Pattern 2: backend proxy

For unwatermarked client-side images, route through your own server:

[Browser] --GET /api/plane/A320--> [Your backend] --GET /v1/images/plane (with key)--> [Aeromodel API]

Express / Node.js

import express from "express";

const app = express();
const KEY = process.env.AEROMODEL_API_KEY; // server-side only

app.get("/api/plane/:slug", async (req, res) => {
  const url = new URL("https://api.aeromodel.dash-systems.fr/v1/images/plane");
  url.searchParams.set("plane", req.params.slug);
  url.searchParams.set("airline", req.query.airline ?? "");
  url.searchParams.set("resolution", "card");
  url.searchParams.set("align", "bottom");

  const upstream = await fetch(url, { headers: { "x-api-key": KEY } });
  res.setHeader("content-type", upstream.headers.get("content-type"));
  res.setHeader("cache-control", "public, max-age=86400");
  upstream.body.pipe(res);
});

Cloudflare Worker (zero-config proxy)

export default {
  async fetch(request, env) {
    const url = new URL(request.url);
    const upstream = new URL("https://api.aeromodel.dash-systems.fr/v1/images/plane");
    for (const [k, v] of url.searchParams) upstream.searchParams.set(k, v);
    return fetch(upstream, { headers: { "x-api-key": env.AEROMODEL_KEY } });
  }
};

Next.js route handler

// app/api/plane/route.ts
export async function GET(req: Request) {
  const incoming = new URL(req.url);
  const upstream = new URL("https://api.aeromodel.dash-systems.fr/v1/images/plane");
  for (const [k, v] of incoming.searchParams) upstream.searchParams.set(k, v);
  const r = await fetch(upstream, { headers: { "x-api-key": process.env.AEROMODEL_KEY! } });
  return new Response(r.body, {
    status: r.status,
    headers: {
      "content-type": r.headers.get("content-type") ?? "image/png",
      "cache-control": "public, max-age=86400"
    }
  });
}

✅ Pattern 3: signed URLs (roadmap)

Roadmap — /v1/sign endpoint generating short-lived signed image URLs. Lets you serve client URLs without revealing the key. Not yet available.

Storing the key in production

PlatformMethod
Cloudflare Workerswrangler secret put AEROMODEL_API_KEY
Vercel / NetlifyEnv vars (without NEXT_PUBLIC_ / VITE_)
AWS LambdaAWS Secrets Manager or Lambda env vars
DockerDocker secret, gitignored .env file
GitHub Actions${{ secrets.AEROMODEL_API_KEY }}
Local dev.env.local (in .gitignore)

What to do if a key leaks

  1. Contact the admin immediately to rotate (wrangler secret put API_KEYS with the new value).
  2. Find the source of the leak (commit, screenshot, public log...).
  3. Check abnormal requests in Cloudflare Workers Analytics.
  4. Update your backend services with the new key.

See also