JOGL Network Docs

REST API

The versioned /v1 HTTP surface — search, self-enrichment, community members, and enrichment.

The public REST API is a versioned /v1 HTTP surface served by the api-gateway edge function. Business logic lives in transport-agnostic handlers shared with the MCP server, so the two never diverge.

The machine-readable contract is openapi.yaml at the repo root — load it into Swagger UI / Redoc or generate a client from it. The narrative reference is docs/API_V1.md. This page is a summary; the spec is the field-level source of truth.

Base URL

Endpoints are served under the api-gateway function on your target Supabase project:

https://<project-ref>.supabase.co/functions/v1/api-gateway
EnvironmentProject ref
Productionohtxbovwsyktbjldbjao
Stagingopkcrawzztcovawrteho
Devudsgxgdircziocvqcvrv

Authenticate with an API key (see Authentication).

Error envelope

Every non-2xx response is a uniform envelope:

{ "error": { "code": "not_found", "message": "…", "request_id": "…" } }

Common codes include bad_request / invalid_request (400), unauthorized (401), forbidden (403), not_found (404), conflict (409), unprocessable (422), owner_consent_required (422), rate_limited (429), search_unavailable, and internal (500). This is not exhaustive — treat the openapi.yaml error-code enum as the complete, authoritative list, and parse unknown codes leniently (new codes are additive, see Versioning). Every response carries an X-Request-Id header — quote it when reporting an issue.

Endpoints

Identity

Method & pathScopePurpose
GET /v1/meanyKey identity, owner, scopes, usage, credit balance
GET /v1/me/profileprofile:readRead your own profile
POST /v1/me/enrichself:enrichStart a self-enrich run (target-locked; see billing note below)
GET /v1/me/enrich/runs/{run_id}self:enrichPoll a self-enrich run

Self-enrich billing. A self-enrich via the API is treated as an intentional, cost-aware call: for a key whose owner is on a paid plan it is billable at 1 credit via the enrichment_self marker. Post-hoc metering for this marker is live on production (it debits real credits today) — what is not yet enabled is hard blocking, so an insufficient balance does not fail the call yet, but it will return a 402 once enforcement is turned on. Owners not on a paid plan are not charged but are subject to the 30-day cooldown. Don't assume it is free.

POST /v1/search (scope search:read) runs expert search and returns ranked matches.

{ "query": "battery electrochemistry researchers", "scope": "community",
  "community_id": "…", "limit": 20 }
  • scope is one of community (needs community_id), all (your authorized communities plus public claimed profiles), or public (public claimed profiles only). Use community if you want a single-community corpus with no public matches mixed in.
  • Scopes are fail-closed and fenced server-side to what your key is authorized for; an unauthorized community_id returns 403, never a silent empty result.

Async by design. A full search runs embed → retrieve → rerank and can take 35–60s+, longer than most agent clients' request timeout. So the call waits only up to wait_seconds and then returns one of:

  • 200 { "status": "complete", "search_id", "matches": [...] } — finished in time.
  • 202 { "status": "pending", "search_id", "poll_after_seconds" } — still running; poll GET /v1/search/{search_id} until complete or failed.

Each match carries { profile_id, user_id, name, headline, organization, location, avatar_url, score, semantic_score, explanation, shared_communities }.

Community members

Method & pathScopePurpose
GET /v1/communities/{id}/membersprofile:readList the roster (keyset pagination)
GET /v1/communities/{id}/members/{profile_id}profile:readRead one enriched member
POST /v1/communities/{id}/membersmember:writeAdd people (bulk, per-item results)
DELETE /v1/communities/{id}/members/{profile_id}member:writeCommunity-scoped erasure (DSAR)

List responses use keyset pagination: pass ?limit= (default 50, max 200) and ?after= (an opaque cursor), and page until next_cursor is null — that is the only exhaustion signal.

Enrichment (write)

Method & pathScopePurpose
POST /v1/communities/{id}/enrichenrich:writeStart a Smart Enrich run on members
GET /v1/communities/{id}/enrich/runs/{run_id}enrich:readPoll a community enrichment run

The enrich body is all-optional and composable: depth (quick | standard | deep), profile_ids, joined_since, include_already_enriched, and dry_run (preview the selection and estimated credits without starting a run). See Enrichment for what each depth tier does.

Idempotency

Only the two community write POSTs honor an optional Idempotency-Key header (1–255 printable chars): POST /v1/communities/{id}/enrich and POST /v1/communities/{id}/members. A replay with the same key + same body returns the original stored response verbatim; the same key with a different body returns 422.

Everything else ignores the header — including POST /v1/me/enrich, the DELETE …/members/{profile_id} erasure, search, and the reads. In particular, retrying POST /v1/me/enrich with the same key is not de-duplicated, so a retry after a timeout can start a second self-enrich run; handle that on the client.

Versioning

/v1 is the stability contract. Only backward-compatible changes ship within it (new endpoints/fields/enum values/error codes); clients must tolerate unknown fields. Breaking changes ship only under a new major version (/v2), served side-by-side.

On this page