Public API and documentation
One OpenAPI contract feeding Blume Pages, Scalar, and OpenWiki.
Outward-facing platform surface for BLI-66: documented REST API, scoped tokens, webhook subscriptions, and a permission-filtered OData v4 BI service. Linear issue BLI-66 owns product scope; the committed OpenAPI artifact owns the currently published HTTP contract.
Entry URLs
| Surface | Where |
|---|---|
| Partner guides (this site) | /partner · Pages: https://supreme-adventure-r2rn151.pages.github.io/partner |
| Developer map (this site) | /developers |
| OpenAPI JSON (Pages) | /openapi.json — primary published reference |
| OpenAPI JSON (app) | GET /api/v1/openapi.json |
| Scalar reference (deployed staff app) | GET /reference — see Scalar API reference for the auth reality and runtime-vs-committed distinction |
| Scalar local preview (developers only) | http://localhost:3000/reference after pnpm dev |
Contract source of truth
Nothing below is a second source — all consumers take the same artifact:
- Zod schemas in
packages/api-contract/src/ - → OpenAPI 3.1 via
@asteasolutions/zod-to-openapi - → committed
packages/api-contract/openapi.json(pnpm --filter @blinqx/api-contract gen) - → live
GET /api/v1/openapi.jsononapps/web
Four layers over one spec
Caption: one generated contract; Blume and OpenWiki symlink it; Scalar renders the live app generator.
Symlinks (committed)
apps/docs/openapi.json → packages/api-contract/openapi.json
apps/docs/public/openapi.json → packages/api-contract/openapi.json
openwiki/integrations/openapi.json → packages/api-contract/openapi.json
Verify: docs/runbooks/docs-surfaces.md.
Partner narrative
Guides under /partner cover scoped tokens, scopes/can(), pagination, idempotency (not yet in the contract), rate limits, webhook subscriptions, and OData.
Published capability map
| Capability | Published paths | Scope | Contract boundary |
|---|---|---|---|
| REST resources | /api/v1/matters, /relations, /documents, /hours, /tasks, /invoices |
Resource-specific read/write scopes; invoices currently publish billing:read only |
JSON request and response schemas come from OpenAPI |
| Webhook subscriptions | GET and POST /api/v1/webhooks |
webhooks:admin |
List/create and the five event types are published; delivery headers, retry timing, update, and revoke are not yet in OpenAPI |
| OData BI | /api/v1/bi, /api/v1/bi/$metadata, /api/v1/bi/matters, /hours, /billing |
bi:read |
OData v4 discovery and collection envelopes with $top/$skip; no general query-option or DirectQuery promise |
The table deliberately follows packages/api-contract/openapi.json. A route that exists in apps/web but is absent from that artifact is an internal or not-yet-published route.
Authentication and permission flow
Caption: token scope is the coarse gate; the resolved user’s normal permission rule remains authoritative before serialization.
Webhook subscription contract
POST /api/v1/webhooks accepts an event type, callback URL, secret, and optional active flag. The transport adapter authenticates webhooks:admin; the webhook capability layer adds the tenant-admin and callback safety gates; the application handler persists the subscription without returning the secret.
Caption: the public create path applies scope, permission, and callback-safety checks before persistence.
The published event enum is matter.created, relation.created, hour.created, task.created, and invoice.sent. Keep partner docs limited to fields and operations present in OpenAPI; internal delivery implementation is not a substitute for a published signature/retry contract.
OData discovery and paging
The BI service is intentionally small and read-only. An OData-aware client starts at /api/v1/bi, reads /api/v1/bi/$metadata, then requests the matters, hours, or billing entity set. Collection routes reuse the API’s permission filtering before paging and return @odata.context, value, and optional @odata.nextLink.
Caption: OData discovery exposes three permission-filtered entity sets and offset paging without promising unsupported query options.
Change and verification workflow
- Change Zod schemas or operation registration under
packages/api-contract/src/. - Regenerate the committed artifact with
pnpm --filter @blinqx/api-contract gen. - Review the
packages/api-contract/openapi.jsondiff; partner availability wording must follow that artifact. - Run
pnpm --filter @blinqx/api-contract testand the route-focused tests for the affected surface. - Build the docs site so
/openapi.json, partner guides, and this developer map are checked together.
Hard constraints
- EU-only production path for tenant data, auth, AI, observability.
- Every tenant resource is permission-filtered through
can()before serialization. - Bearer tokens hashed at rest and scoped;
/api/v1versioned; list endpoints server-side paged. - Published availability comes from committed OpenAPI, not from an unregistered route or a future Linear acceptance criterion.