Open Discover
Overview
The Open Discover Service API (open-api-disc) lets a client retrieve the Service APIs currently published at the CCF, filtered by a range of optional criteria.
It is called "Open" because, unlike the regular Discover Service API, it does not require the caller to be an onboarded API Invoker. OpenCAPIF still requires a bearer token to call it (see Authentication below), but that token only needs a Register Service account — no invoker onboarding.
Endpoint
GET https://<capifRoot>/open-api-disc/v1/service-apis
<capifRoot> is your CCF host (for example capifcore inside the OpenCAPIF docker/Helm deployment).
Authentication
Every request to this endpoint must carry a bearer token:
Authorization: Bearer <access_token>
To obtain a token:
- Register a user account with the Register Service (or use an account you already have).
- Call
GET /getauthon the Register Service, authenticating with HTTP Basic Auth (the username/password you registered). The response contains: access_token: a JWT to use as your bearer token.ca_root: the CA certificate to verify the CCF's TLS certificate.- a set of convenience URLs, including
ccf_open_discover_url(open-api-disc/v1/service-apis). - Send
access_tokenas theAuthorization: Bearerheader on your Open Discover requests, verifying TLS againstca_root.
Two things worth knowing about how this is enforced, so you are not surprised by the failure mode:
- The reverse proxy in front of the CCF only checks that the
Authorizationheader is present and syntactically looks likeBearer <something>; it does not validate the token itself. If the header is missing entirely, you get a401directly from the proxy (see Errors). - The Open Discover service itself validates the token's signature (RS256) but does not check that the token belongs to a specifically onboarded API Invoker — any valid token issued by the Register Service for any registered user is accepted for this endpoint. If the token is missing, expired, or has an invalid signature once it reaches the service, you get a different
401response shape than the proxy-level one (see below).
Unlike several other CAPIF endpoints in this platform, this route does not require a mutual-TLS client certificate.
Query parameters
All parameters are optional; omitting all of them returns every published Service API. Array-valued parameters use OpenAPI "form" style with explode: false: pass multiple values as one comma-separated parameter, for example api-names=service_1,service_2 — not api-names[]=... or bracket/JSON array syntax.
| Parameter | Type | Description | Multiple values mean |
|---|---|---|---|
api-names |
array(string) | Name(s) of the target Service API(s). | Any of these names |
api-ids |
array(string) | Identifier(s) of the target Service APIs. | Any of these IDs |
api-cats |
array(string) | Category(ies) of the target Service API(s). | Any of these categories |
api-prov-names |
array(string) | Name(s) of the provider(s) of the target Service API(s). | Any of these provider names |
api-versions |
map(array(string)) | Major version(s) of the target API(s), keyed by API name (only relevant together with api-names). |
Currently requires the API to support all listed versions, not just one — see caveat below |
comm-type |
string | Communication type supported by the target API(s) (e.g. REQUEST_RESPONSE). |
n/a (single value only) |
protocols |
array(string) | Protocol(s) supported by the target API(s) (e.g. HTTP_1_1, HTTP_2). |
Currently requires the API to support all listed protocols — see caveat below |
data-format |
string | Data format supported by the target API(s) (e.g. JSON). |
n/a (single value only) |
preferred-aef-loc |
object | Preferred AEF location; ignored if there is no matching record. Send as a JSON object, e.g. preferred-aef-loc={"dcId":"dc1"}. |
n/a |
api-supported-features |
map(object) | Feature(s) supported by the API(s) named in api-names, keyed by API name. Only valid together with api-names. |
Any of the listed (API name, feature) pairs |
service-kpis |
object | Service characteristics of the target API(s) (e.g. maxReqRate, availability). |
n/a |
res-ops |
array(object) | Supported resource(s)/operation(s), e.g. {"resource":"...","operations":["GET"]}. |
n/a |
supported-features |
string | Client-side feature negotiation bitmap. Send only when negotiating a feature. | n/a |
| vendor-specific parameters | — | Vendor-specific query parameters, used in addition to the parameters above. | — |
Caveat on api-versions and protocols: as of this writing, requesting more than one value for these two parameters returns only APIs that satisfy every listed value, rather than any one of them. Whether "any" or "all" is the intended semantics has not been confirmed against a project decision; treat this as current behaviour, not a guaranteed contract, until it is confirmed.
Fixed 2026-08: api-names, api-ids, api-cats, and api-prov-names previously returned no results at all (404) whenever more than one value was requested, because the values were combined as if an API had to match every one simultaneously — impossible for these single-valued attributes. This has been corrected so that a multi-value request returns any API matching at least one of the listed values.
Errors
All error responses use the CAPIF ProblemDetails shape (title, status, detail, cause, and optionally invalidParams).
| Status | Cause | When it happens |
|---|---|---|
| 401 Unauthorized | detail: "Access token not present", cause: "Bearer token is required for this API route" |
No Authorization header sent at all (rejected by the reverse proxy, before reaching the service). |
| 401 Unauthorized / 422 | (default flask-jwt-extended error body, not the ProblemDetails shape) |
An Authorization: Bearer header is present but the token is missing, malformed, expired, or has an invalid signature once it reaches the service. |
| 400 Bad Request | detail: "Invalid query parameter format", cause: "preferred-aef-loc must be sent as an application/json query parameter" |
preferred-aef-loc sent using bracket notation instead of a JSON object. |
| 400 Bad Request | detail: "Invalid query parameter format", cause: <exception message> |
Any other query parameter value that cannot be parsed as required (e.g. malformed JSON for an object-shaped parameter). |
| 404 Not Found | detail: "No API Published accomplish filter conditions" |
The request is well formed, but no published Service API matches the given filters (or none are published at all). |
| 500 Internal Server Error | detail: "An exception occurred in open discover services", cause: <exception message> |
An unexpected server-side error. |
Example requests
Retrieve every published Service API:
curl -s https://capifcore/open-api-disc/v1/service-apis \
--cacert ca_root.crt \
-H "Authorization: Bearer $ACCESS_TOKEN"
Filter by one or more API names:
curl -s "https://capifcore/open-api-disc/v1/service-apis?api-names=service_1,service_2" \
--cacert ca_root.crt \
-H "Authorization: Bearer $ACCESS_TOKEN"
Filter by preferred AEF location:
curl -s 'https://capifcore/open-api-disc/v1/service-apis?preferred-aef-loc={"dcId":"dc1"}' \
--cacert ca_root.crt \
-H "Authorization: Bearer $ACCESS_TOKEN"
Related pages
- Register Service — how to register a user and obtain the bearer token used above.
- Open Discover Service API test plan — the automated test scenarios covering this endpoint.