API documentation
v2 contract. When in doubt, the server code is authoritative.
https://api-binformed.gericos.comAuthentication: httpOnly token cookie (send requests with credentials: 'include') or Authorization: Bearer <token>. Sending notifications: X-API-Key. Emails are normalized (lowercase/trim).
1) Authentication & registration
Short JWT access token (15 min) + opaque rotating refresh token. On 401, make one /v1/auth/refresh then replay the request.
POST/v1/auth/signup
/v1/auth/signupCreates an unverified account and sends the verification email. CAPTCHA (Turnstile) required once the server enables it.
curl -X POST https://api-binformed.gericos.com/v1/auth/signup \
-H "Content-Type: application/json" \
-d '{"email":"user@example.com","password":"your-password","captcha_token":"<turnstile>"}'
# -> { "ok": true, "verification_required": true }Password ≥ 8; disposable emails refused. After signup: “Verify your email” screen (no direct login).
POST/v1/auth/resend-verification
/v1/auth/resend-verificationResends the verification link. Generic response (no account enumeration).
curl -X POST https://api-binformed.gericos.com/v1/auth/resend-verification \
-H "Content-Type: application/json" -d '{"email":"user@example.com"}'GET/v1/auth/verify?token=…
/v1/auth/verify?token=…Link clicked in the browser (single-use token, 24 h) → HTML page served by the API. Nothing to code on the front.
POST/v1/auth/login
/v1/auth/loginReturns token + refresh_token (and sets the cookie). No longer returns api_key. 403 email_not_verified if the account is unconfirmed.
curl -s -X POST https://api-binformed.gericos.com/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"user@example.com","password":"your-password"}'
# -> { "token": "<JWT 15 min>", "refresh_token": "<opaque>", "refresh_expires_at": 1739999999 }POST/v1/auth/refresh
/v1/auth/refreshRotation: returns a new pair and resets the cookie; the old refresh is revoked.
curl -s -X POST https://api-binformed.gericos.com/v1/auth/refresh \
-H "Content-Type: application/json" -d '{"refresh_token":"<your-refresh-token>"}'
# -> { "token": "…", "refresh_token": "…", "refresh_expires_at": … }POST/v1/auth/logout
/v1/auth/logoutAuthenticated. Revokes all refresh tokens and clears the cookie.
curl -s -X POST https://api-binformed.gericos.com/v1/auth/logout \
-H "Authorization: Bearer <JWT>" -H "Content-Type: application/json" -d '{}'GET/v1/me
/v1/meCurrent profile: { id, email, created_at }. No more api_key.
2) API key
POST/v1/keys/rotate
/v1/keys/rotateAuthenticated. The only way to obtain/reset the API key, shown once (format gn_…, stored hashed). Regenerating immediately invalidates the old one.
curl -s -X POST https://api-binformed.gericos.com/v1/keys/rotate \
-H "Authorization: Bearer <JWT>" -H "Content-Type: application/json" -d '{}'
# -> { "api_key": "gn_XXXXXXXX…" }3) Devices
POST/v1/devices/register
/v1/devices/registercurl -s -X POST https://api-binformed.gericos.com/v1/devices/register \
-H "Authorization: Bearer <JWT>" -H "Content-Type: application/json" \
-d '{"platform":"android","fcm_token":"<FCM/APNS token>","app_version":"1.0"}'platform ∈ "android" | "ios" (validated).
POST/v1/devices/unregister
/v1/devices/unregistercurl -s -X POST https://api-binformed.gericos.com/v1/devices/unregister -H "Authorization: Bearer <JWT>" \
-H "Content-Type: application/json" -d '{"fcm_token":"<FCM token>"}'
curl -s -X POST https://api-binformed.gericos.com/v1/devices/unregister -H "Authorization: Bearer <JWT>" \
-H "Content-Type: application/json" -d '{"all": true}'GET/v1/devices?limit=&offset=
/v1/devices?limit=&offset=The fcm_token is not exposed.
4) Sending notifications
POST/v1/notify
/v1/notifyAuth via X-API-Key or Bearer. message required (≤ 2000), title ≤ 200, url must be https. Refused (403) if the account is unverified.
curl -s -X POST https://api-binformed.gericos.com/v1/notify \
-H "Content-Type: application/json" -H "X-API-Key: <your-api-key>" \
-d '{"title":"Build finished","message":"CI OK","url":"https://example.com/build/123"}'
# -> { "ok": true, "pushed": 1, "failed": 0 }5) Message history
GET/v1/messages?days=&limit=&before=
/v1/messages?days=&limit=&before=Paginated (keyset). days default 30, max 365; limit default/max 500; before = cursor (messages with strictly lower id). id stable, ts in ms.
curl -s -X GET 'https://api-binformed.gericos.com/v1/messages?days=365&limit=500' -H "Authorization: Bearer <JWT>"
# -> {
# "items": [ { "id": 128, "title": "…", "body": "…", "url": "https://…", "ts": 1752345600000 } ],
# "paging": { "limit": 500, "has_more": true, "next_before": 97 }
# }Next page: pass next_before into ?before= until has_more: false. Client-side dedup via id.
6) Account export & deletion
GET/v1/me/export[?format=zip]
/v1/me/export[?format=zip]GDPR export: JSON, or ZIP (JSON + CSV per collection).
curl -L -X GET 'https://api-binformed.gericos.com/v1/me/export?format=zip' -H "Authorization: Bearer <JWT>" -o export.zipDELETE/v1/me/delete
/v1/me/deleteDeletes the account and all data (cascade, irreversible).
7) Errors
JSON responses { "error": "<code>" } with HTTP status:
400—invalid email,password too short (min 8),disposable_email_not_allowed,captcha_failed,url must be https,missing_refresh_token401—invalid credentials,Invalid token(→ try a refresh),invalid_refresh,invalid api key403—email_not_verified(login & notify),cors_forbidden409—email exists429—too_many_attempts(10 / 15 min / IP),signup_ip_daily_limit
8) Security
- HTTPS only; notification
urlforced tohttps. - Short access token (15 min); refresh opaque, stored hashed and rotated.
- Per-user API keys, stored hashed, regenerable via
/v1/keys/rotate. - CORS: origin allowlist with
Access-Control-Allow-Credentials. - Hardened signup: CAPTCHA + disposable blocking + mandatory email verification.