Single Vercel deployment that proxies public catalog APIs to each catalog’s own project (typically *.vercel.app). Use this when you want one hostname (for example https://api.fides.community) for credential, organization, issuer, wallet, and future catalogs.
Each catalog must already be deployed to Vercel with working routes, for example:
- Credential:
GET /api/public/credentialtype,GET /api/public/credentialtype/{id},GET /api/public/api-docs(upstream path; on the gateway usecredential-api-docs— see Step 3). - Organization:
GET /api/public/organization,GET /api/public/organization/{id},GET /api/public/api-docs(upstream; on the gateway useorganization-api-docs). - Issuer:
GET /api/public/issuer,GET /api/public/issuer/{id},GET /api/public/api-docs(upstream; on the gateway useissuer-api-docs). - Wallet:
GET /api/public/wallet, wallet detail path, andGET /api/public/api-docs(upstream; on the gateway usewallet-api-docsfor the OpenAPI spec).
Use each project’s production https://<name>.vercel.app URL as upstream — not the gateway hostname — or you will create a proxy loop.
| Catalog | List | Detail | OpenAPI JSON | Swagger UI |
|---|---|---|---|---|
| Credential | /api/public/credentialtype |
/api/public/credentialtype/{id} |
/api/public/credential-api-docs |
/swagger-credentialtype.html |
| Organization | /api/public/organization |
/api/public/organization/{id} |
/api/public/organization-api-docs |
/swagger-organization.html |
| Issuer | /api/public/issuer |
/api/public/issuer/{id} |
/api/public/issuer-api-docs |
/swagger-issuer.html |
| Wallet | /api/public/wallet |
/api/public/wallet/{orgId}/{walletId} |
/api/public/wallet-api-docs |
/swagger-wallet.html |
Legacy 308 redirects: /api/public/api-docs and /swagger.html → credential equivalents (old links keep working).
The gateway forwards issuer query parameters unchanged to the issuer upstream. Current issuer list filters include:
searchenvironmentorgIdvcFormatcredentialCatalogIdsubjectTypetagscountrysort,direction,page,size
This gateway exposes RFC 9727 api-catalog discovery:
- URL:
GET/HEADhttps://<gateway>/.well-known/api-catalog - Format:
application/linkset+jsonwith profilehttps://www.rfc-editor.org/info/rfc9727 - Implementation:
api/well-known-api-catalog.ts, rewritten invercel.jsonfrom/.well-known/api-catalog
HEAD responses include a Link header with rel="api-catalog" as required by the RFC.
lib/gatewayCatalogs.ts is the single place to update when you add, remove, or rename gateway routes for a catalog (list path, OpenAPI path, Swagger HTML, upstream env var name). It feeds:
| Consumer | Purpose |
|---|---|
api/public/catalogs.ts |
JSON list of catalogs and paths (configured follows upstream env vars) |
api/well-known-api-catalog.ts |
RFC 9727 Linkset: item links to each configured catalog’s list endpoint |
If you add a new proxy under api/public/ but forget to extend GATEWAY_CATALOG_ROUTES, automated discovery and agent-oriented tools will be out of date even if the route works.
Checklist when changing the public API surface
- Edit
lib/gatewayCatalogs.ts(GATEWAY_CATALOG_ROUTES, andGatewayCatalogIdif you add a catalog). - Add or adjust serverless handlers and
vercel.jsonredirects if paths change. - Redeploy and verify
/api/public/catalogsand/.well-known/api-catalog(withAccept: application/linkset+json).
The gateway also exposes an MCP (Model Context Protocol) server so the FIDES
Ecosystem Explorer can be added as an "app"/connector in ChatGPT, Claude, and
other MCP clients. It covers all configured catalogs; see
docs/MCP-IMPLEMENTATION-PLAN.md for the design.
- Endpoint (Streamable HTTP):
POST https://<gateway>/api/mcp - Implementation:
api/mcp.ts(viamcp-handler); tool layer inlib/(catalogClient.ts+*Tools.ts, aggregated bycatalogTools.ts). - Catalog tools:
search_wallets/get_wallet,search_credential_types/get_credential_type,search_organizations/get_organization,search_issuers/get_issuer. - Generic tools:
search(federated across all catalogs) andfetch(retrieve a record by result id) — the shapes ChatGPT uses for connectors / Deep Research, returning canonical URLs for citations. - Requires: the relevant
FIDES_*_CATALOG_ORIGINset per catalog; optionalGATEWAY_PUBLIC_ORIGIN(defaults tohttps://api.fides.community) for canonical links in tool output. A catalog whose origin env is unset is simply skipped by the genericsearch. - Runs stateless (no Redis); read-only and unauthenticated like the rest of the gateway.
- Claude (claude.ai / Desktop): Settings → Connectors → Add custom
connector → URL
https://<gateway>/api/mcp. - ChatGPT: Settings → Apps & Connectors → Advanced → enable Developer
Mode → Create → URL
https://<gateway>/api/mcp. - Any MCP client (Cursor, MCP Inspector, API Playground): point it at the
same
/api/mcpURL.
npm run typecheck
npx @modelcontextprotocol/inspector # connect to https://<gateway>/api/mcp, list toolsNote: the dependency-only
npm auditwarnings come from@vercel/nodetransitive packages (tar/undici), not from the MCP packages.
The gateway also hosts the backend for a chat assistant on the FIDES
homepage. It reuses the same catalog tool layer as the MCP server (no
duplication): lib/toolRegistry.ts replays the shared tool registration into an
in-memory registry, exposes a JSON-Schema view for LLM function calling, and the
agent calls those handlers directly — no MCP transport internally.
- Endpoint:
POST https://<gateway>/api/chat, body{ "messages": [{ "role": "user", "content": "..." }] }. - Response:
text/event-stream(SSE) withtoken,sources,done, anderrorevents.sourcescarries citable{ title, url, type }detail pages. - Implementation:
api/chat.ts(Fetch-style, likeapi/mcp.ts) →lib/chatAgent.ts(tool-calling loop) →lib/llm.ts(provider adapter) +lib/rateLimit.ts. - LLM provider: OpenAI-compatible
/chat/completionsadapter. Default is Mistral (EU/GDPR-conscious);openaiandazurework via env only. The provider key (LLM_API_KEY) is server-side only — never in WordPress or the browser. - Grounding: the system prompt forbids answering without tool data and
requires linking to canonical
api.fides.communitydetail URLs; answers follow the language of the question (NL/EN). - Site-content search (
lib/siteTools.ts): an optionalsearch_site_contenttool answers conceptual/general questions ("what is a business wallet", what FIDES is, manifesto, use cases, news) from the public FIDES website over the WordPress REST API (/wp-json/wp/v2/pages|posts), returning short citable page excerpts. Kill switch: enabled by default; setCHAT_SITE_CONTENT_ENABLED=0to remove the tool entirely (chat falls back to catalog-only answers). Site origin isFIDES_SITE_ORIGIN(defaulthttps://fides.community). - Cost controls (public endpoint): per-IP rate limit
(
CHAT_RATE_LIMIT_PER_MIN) + daily approximate-token budget (CHAT_DAILY_TOKEN_BUDGET). Uses Upstash Redis (REST) when configured, otherwise per-instance in-memory counters.CHAT_ALLOWED_ORIGINSrestricts the browser origins permitted to call the endpoint. - Usage logging (
lib/chatLog.ts): when Upstash is configured, each turn is logged anonymously to a per-day listchat:log:YYYY-MM-DD— the question text plus lightweight metadata (ok, approxtokens, source count + counts per catalog type). No IP, no session id, and no answer text are stored. The list auto-expires (CHAT_LOG_RETENTION_DAYS, default 90) and is capped per day (CHAT_LOG_MAX_PER_DAY, default 5000). Disable withCHAT_LOG_ENABLED=0. This is for understanding what visitors ask so the catalogs/site can be improved.
See .env.example for all chat env vars and docs/MCP-IMPLEMENTATION-PLAN.md
→ section 4 for the design. The WordPress chat widget lives in the
fides-assistant plugin.
- In Vercel: Add New… → Project and import the fides-organization-catalog GitHub repository.
- Root directory: repository root (must contain
vercel.json,package.json,api/,public/). - Leave Build / Output to the values from
vercel.json(npm ci,outputDirectory: public, no framework). - Deploy and open the Production URL, for example
https://fides-organization-catalog.vercel.app. - Verify:
GET …/api/public/organization?page=0&size=5GET …/api/public/api-docs(OpenAPI on the organization project itself)- Optional:
…/swagger.html(on the organization project)
Copy this production base URL (no trailing slash) for Step 3.
If the credential catalog is already on Vercel, copy its production *.vercel.app base URL the same way.
If api.fides.community is currently assigned to the credential project, that domain is not the value you put in env vars here — use the underlying .vercel.app URL from the Vercel dashboard (Project → Domains / deployment URL).
-
Create a new Vercel project from this repository (
fides-api-gateway). -
In Settings → Environment Variables (Production), set:
Name Example value FIDES_CREDENTIAL_CATALOG_ORIGINhttps://fides-credential-catalog.vercel.appFIDES_ORGANIZATION_CATALOG_ORIGINhttps://fides-organization-catalog.vercel.appFIDES_ISSUER_CATALOG_ORIGINhttps://fides-issuer-catalog.vercel.appFIDES_WALLET_CATALOG_ORIGINhttps://fides-wallet-catalog.vercel.appSee
.env.examplefor the full list. Omit an origin if you do not want that catalog on this gateway yet. -
Redeploy after saving variables.
-
Test the gateway production URL:
/api/public/catalogs/.well-known/api-catalog(RFC 9727 Linkset; useAccept: application/linkset+jsonif your client negotiates)/api/public/credentialtype/api/public/credential-api-docs/api/public/organization/api/public/issuerand/api/public/issuer-api-docs(whenFIDES_ISSUER_CATALOG_ORIGINis set)/swagger-credentialtype.html,/swagger-organization.html,/swagger-issuer.html,/swagger-wallet.html- When
FIDES_WALLET_CATALOG_ORIGINis set:/api/public/walletand wallet detail URLs - Legacy (308 redirect):
/api/public/api-docs→ credential spec;/swagger.html→ credential Swagger
Use this when the gateway is already verified on its *.vercel.app URL (Step 3) and upstream env vars use those *.vercel.app bases — never the public API hostname (avoids a proxy loop).
-
https://<gateway>.vercel.app/api/public/catalogsshows each catalog you need asconfigured: true. -
https://<gateway>.vercel.app/api/public/credentialtypereturns data (proxies to credential backend). -
FIDES_CREDENTIAL_CATALOG_ORIGINin the gateway project is the credential project’s.vercel.appURL, nothttps://api.fides.community.
A hostname can only be attached to one Vercel project at a time.
-
Credential catalog project (where
api.fides.communityis today): Settings → Domains → findapi.fides.community→ Remove (or “Edit” → remove).- The credential API stays available at its
*.vercel.appURL for the gateway upstream.
- The credential API stays available at its
-
Gateway project: Settings → Domains → Add → enter
api.fides.community→ confirm. -
If Vercel shows DNS instructions (CNAME / A record): apply them at your DNS host (often the same records you used for the credential project; Vercel will show the current expected values). Wait until the domain shows Valid on the gateway project.
-
Redeploy the gateway if Vercel suggests it after the domain change (usually not strictly required, but safe).
- Public URLs become:
https://api.fides.community/api/public/credentialtype,/api/public/organization,/api/public/issuer,/api/public/wallet, etc. - Do not change upstream env vars to
https://api.fides.community— keep*.vercel.apporigins.
If something goes wrong: remove the domain from the gateway project, add it back to the credential project, fix DNS if needed, then debug the gateway on *.vercel.app again before retrying.
npm ci
npm run typecheckUse Vercel CLI vercel dev with a local .env mirroring .env.example to exercise proxies locally.
Issuer and wallet use the same pattern (FIDES_*_CATALOG_ORIGIN, dedicated *-api-docs and Swagger HTML) once each catalog is deployed to Vercel.
For the RP catalog:
- Add the serverless API pattern in that repo (see
credential-catalog/API_SETUP.md). - Deploy to Vercel; note its
*.vercel.apporigin. - In this gateway: new env var, proxy handlers, extend
lib/gatewayCatalogs.ts(andGatewayCatalogId), updatepublic/index.htmlif you list catalogs there, then verify/api/public/catalogsand/.well-known/api-catalog.