Health, identity & meta endpoints
Health, identity & meta endpoints
These are the small, supporting endpoints that sit alongside the fiscal API surface. They exist for operational concerns rather than business logic: liveness and readiness probes for load balancers and orchestrators, an identity introspection call so an integration can confirm which key (or user) it is currently authenticating as, a robots exclusion file so search engines never index the API host, and the OpenAPI surface itself so Postman, SDK code generators and human readers can discover every other endpoint without credentials.
All of them are routed at the root of the host, not under /api/v1/, because they are infrastructure rather than versioned business endpoints. The only one that requires authentication is GET /api/v1/me.
GET /health
Cheapest possible liveness check. Does no I/O — just answers with the current timestamp and the package version of the running build. Use it for load balancer health checks, Kubernetes livenessProbe, AWS Target Group health checks and any other "is the process up?" probe.
- Auth: none — public.
Response (200 OK)
| Field | Type | Notes |
|---|---|---|
status | string | Always "ok". If you cannot reach the endpoint, the process is down. |
timestamp | string (ISO 8601) | Server clock at the moment of the response. |
version | string | The API package version (process.env.npm_package_version), or "0.0.0" when not set. |
Example
curl https://api.e-bon.ro/health
{
"status": "ok",
"timestamp": "2026-04-09T08:10:00.000Z",
"version": "0.0.0"
}
GET /health/firebase
End-to-end Firestore connectivity check. The handler writes a temporary document to the _health collection, reads it back, and deletes it — so a 200 confirms credentials, network reachability and the read+write path against the live database. The total round-trip is reported in latencyMs.
- Auth: none — public.
Responses
200 OK — Firestore is reachable end to end:
| Field | Type | Notes |
|---|---|---|
status | string | Always "ok". |
firestore | string | Always "connected". |
latencyMs | integer | Write + read + delete round-trip, milliseconds. |
timestamp | string (ISO 8601) | Server clock at the moment of the response. |
503 Service Unavailable — Firestore is unreachable. The body has one of two shapes depending on where the failure happened:
Underlying Firestore call threw (typical case — credentials, network, permission denied):
| Field | Type | Notes |
|---|---|---|
status | string | Always "error". |
firestore | string | Always "disconnected". |
message | string | The thrown error message (or "Unknown error"). |
latencyMs | integer | Time spent before the failure surfaced, milliseconds. |
Read-back returned an empty snapshot (the write succeeded but the document is not visible — extremely rare, usually indicates a Firestore consistency anomaly):
| Field | Type | Notes |
|---|---|---|
status | string | Always "error". |
message | string | Always "Firestore read-back failed". |
latencyMs | integer | Round-trip up to and including the failed read-back. |
status first — the second 503 shape does not include the firestore field. Do not rely on its presence.Example
curl https://api.e-bon.ro/health/firebase
{
"status": "ok",
"firestore": "connected",
"latencyMs": 42,
"timestamp": "2026-04-09T08:10:00.000Z"
}
GET /health/ready
Full readiness check. Aggregates per-component health under a single response so an orchestrator can gate traffic on every external dependency the API needs to do useful work. Today the only component checked is firestore, using the same write+read+delete probe as /health/firebase (against the _health/ready document); future external dependencies will appear as additional keys under components.
- Auth: none — public.
Responses
200 OK — every component is healthy.
503 Service Unavailable — at least one component is unhealthy.
The body shape is identical for both status codes:
| Field | Type | Notes |
|---|---|---|
status | string | "ok" when every component is "ok", "error" otherwise. |
components.firestore.status | string | "ok", "error" or "skipped". |
components.firestore.latencyMs | integer | Round-trip for the Firestore probe, milliseconds. |
components.firestore.message | string (optional) | Present when status is "error". Either the underlying error message or "Firestore read-back failed". |
timestamp | string (ISO 8601) | Server clock at the moment of the response. |
Example
curl https://api.e-bon.ro/health/ready
{
"status": "ok",
"components": {
"firestore": { "status": "ok", "latencyMs": 38 }
},
"timestamp": "2026-04-09T08:10:00.000Z"
}
GET /api/v1/me
Identity introspection. Echoes back the orgId, scopes and keyLabel of the credential that authenticated the request. Useful as a one-shot check that a freshly issued API key is wired up correctly, or for an admin UI that wants to display "you are signed in as X".
- Auth: required — API key or Portal JWT (combined auth).
Response (200 OK)
| Field | Type | Notes |
|---|---|---|
orgId | string | The organization the credential belongs to. |
scopes | string | The scopes attached to the API key. See Authentication › Scopes for the canonical list. |
keyLabel | string | The human-readable label given to the API key when it was created. |
Errors
UNAUTHORIZED(401) — no credential, malformed credential, or the key is inactive / revoked.
Examples
With an API key (the most common case):
curl https://api.e-bon.ro/api/v1/me \
-H "Authorization: Bearer ebon_live_acme_corp_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"
Same call with the alternative x-api-key header form:
curl https://api.e-bon.ro/api/v1/me \
-H "x-api-key: ebon_live_acme_corp_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"
With a Portal JWT (the Portal and the mobile app use this flow):
curl https://api.e-bon.ro/api/v1/me \
-H "Authorization: Bearer eyJhbGciOi..."
{
"orgId": "acme_corp",
"scopes": ["receipts", "commands", "devices:read"],
"keyLabel": "POS Integration"
}
GET /robots.txt
Robots exclusion file. Returns text/plain with a blanket disallow so that no crawler indexes the API host — the API is not a website and has no content worth indexing.
- Auth: none — public.
Response (200 OK)
Content-Type: text/plain with the body:
User-agent: *
Disallow: /
Example
curl https://api.e-bon.ro/robots.txt
GET /docs and /docs/openapi.json
The full OpenAPI surface, exposed in two flavours so both humans and tooling can discover every endpoint without authentication.
- Auth: none — both routes are public by design so any tool can discover the API contract without credentials.
GET /docs
Swagger UI (rendered HTML). Open it in a browser to browse the endpoint catalogue interactively, expand request/response schemas and try requests against the live API.
https://api.e-bon.ro/docs
GET /docs/openapi.json
The raw OpenAPI 3 specification as a single JSON document. Feed it to Postman ("Import → Link" against this URL), to OpenAPI-aware SDK code generators, or to anything else that can consume an OpenAPI 3 spec.
curl https://api.e-bon.ro/docs/openapi.json
/docs and /docs/openapi.json are intentionally public — they ship the API's public contract, not its data. You can link to them from internal tooling, partner onboarding pages or customer-facing integration guides without worrying about authentication.Use these from a load balancer or uptime monitor
The two probes are designed for different layers of orchestration:
- Liveness probe →
GET /health. Cheap, no external I/O, no Firestore round-trip. Use it for KuberneteslivenessProbe, AWS Target Group health checks, DockerHEALTHCHECKand uptime monitors that should fire only when the process itself is wedged. - Readiness probe →
GET /health/ready. Performs a real Firestore write+read+delete every call. Use it for KubernetesreadinessProbeand any other gate that should keep traffic away from a pod that is up but cannot serve real requests because a downstream dependency is broken.
A minimal Kubernetes example:
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 10
periodSeconds: 30
readinessProbe:
httpGet:
path: /health/ready
port: 3000
initialDelaySeconds: 15
periodSeconds: 30
/health/firebase and /health/ready perform a real Firestore write, read and delete on every request. Do not scrape them every second from an uptime monitor — keep the interval at 30 seconds or higher. For sub-second liveness checks always use /health, which does no I/O.Discover the API surface
For interactive exploration in a browser, point a teammate at https://api.e-bon.ro/docs (Swagger UI). For tooling that wants to consume the spec directly — Postman import via URL, SDK code generators, OpenAPI linters — point them at https://api.e-bon.ro/docs/openapi.json. The curated, hand-organised Postman collection (with example bodies and folders grouped by surface) lives on its own page; see Postman collection.
Next steps
- API overview — base URL, error envelope, rate limits, idempotency and tier gating.
- Authentication — API key format, the canonical scopes list and how to send credentials.
- Postman collection — import the curated collection or feed Postman the raw
/docs/openapi.jsonURL.
Authentication endpoints
REST endpoints under /api/v1/auth — register, login, forgot password, refresh and logout — that issue and revoke the JWT access + refresh token pair used by the e-bon Portal and the E-BON mobile app.
Idempotency
Use the Idempotency-Key header to make POS retries safe — replay cached responses for 24 hours and avoid double-printed receipts.