Public API.

REST. Base path /api/public/v1. Read-only. Returns only entries an IPMERC admin has explicitly marked public. Every request needs an API key.

Access

Keys are issued by an IPMERC administrator. Email the operator to request access. There is no self-service signup, and only entries explicitly toggled public in the admin console are returned.

Authentication

Every request must include an Authorization: Bearer ipmerc_… header. The raw key is shown once at creation; only its hash is stored. Revoked keys return 401.

Rate limits

  • 60 requests per minute per key
  • 3000 requests per hour per key
  • 200 requests per minute per IP (applies before auth)

Every response carries X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset (seconds until the window resets). On 429 a Retry-After header tells you when to retry.

Endpoints

GET/api/public/v1/entries

Paginated list of public entries. Query params: category, type (answer | drill | handout), lang (nl | en), limit (1..200, default 50), offset.

curl "https://ipmerc.com/api/public/v1/entries?limit=10" \
  -H "Authorization: Bearer ipmerc_..."
GET/api/public/v1/entries/:id

One public entry by id. Returns 404 for private or missing ids (existence of private entries is never leaked).

curl https://ipmerc.com/api/public/v1/entries/<uuid> \
  -H "Authorization: Bearer ipmerc_..."
GET/api/public/v1/search

Keyword search across title + body of public entries. Query params: q (required, 1..200 chars), type, lang, limit (1..50, default 20).

curl "https://ipmerc.com/api/public/v1/search?q=cold+call" \
  -H "Authorization: Bearer ipmerc_..."

Response shape

{
  "data": [
    {
      "id": "uuid",
      "type": "answer" | "drill" | "handout",
      "title": "string",
      "questions": ["..."],
      "keywords": ["..."],
      "body": "markdown (answer/handout) | JSON-encoded { dialog, quiz } (drill)",
      "language": "nl" | "en",
      "source": "academy" | "imported" | "external" | "ipmerc",
      "category": { "id": "uuid", "slug": "...", "nameNl": "...", "nameEn": "..." },
      "version": 1,
      "createdAt": "ISO-8601",
      "updatedAt": "ISO-8601"
    }
  ],
  "meta": { "total": 170, "limit": 50, "offset": 0, "returned": 50 }
}

Errors

  • 400 · invalid query parameters
  • 401 · missing or revoked API key
  • 404 · unknown id or category slug (also returned for private entries to avoid leaking existence)
  • 429 · rate limit exceeded (Retry-After header included)
  • 500 · internal error (logged on server)