Skip to content

List the surfaces the caller may use (the surface hub).

GET
/v1/surfaces
curl --request GET \
--url https://example.com/v1/surfaces \
--header 'Authorization: Bearer <token>'

The transport-neutral surface hub: the surfaces the caller may use, for any client to offer (the sign-in page, hf surface list). The list is guidance, not authorization; the PDP and the surface’s ceiling decide at use. Lists the embedded surfaces and every module surface that is declared and has its entry file on disk, filtered to the surfaces the caller can use: a module surface is listed when the caller holds one of its grantable actions at any scope (a module surface with none is listed for nobody); a platform surface with none is listed for everyone. Each entry’s name (the owning module’s qualified key, a :, then the surface key, as in acme.crm:app) identifies the surface; mountPath is where a web surface is served and may change. actions is the surface’s declared action list (its ceiling), present only for a caller who can read the owning module’s metadata. unmounted lists declared surfaces that are not mounted and why; an entry appears only for a caller who can read the owning module’s metadata.

Response envelope for GET /surfaces.

Media typeapplication/json

Response envelope for GET /surfaces.

object
surfaces
required

Surfaces mounted on this server that the caller may see.

Array<object>

One surface entry on the wire.

object
actions

The actions this surface declares: what a token issued to it may do on a user’s behalf, whatever the user is otherwise allowed to do. Present only when the caller can read the owning module’s metadata (for the platform’s own surfaces, module metadata in general); absent otherwise, which says nothing about whether the surface declares any.

Array<string> | null
key
required

Surface key within its module: the second half of name.

string
kind
required

What kind of surface this is: web for a surface the server serves at mountPath.

One of:

A surface the server serves at a mount path.

string
Allowed value: web
label
required

Display label for this surface.

string
module

Owning module’s qualified key. Absent for a surface embedded directly in this binary rather than installed as a module.

string | null
mountPath
required

URL path a web surface is served at. It is unique on the server, and it may change while the surface keeps its name.

string
name
required

Canonical name of the surface: the owning module’s qualified key (vendor.moduleKey, or moduleKey when the module has no vendor), a :, then the surface key. henceforth:studio for the platform’s own surfaces, acme.crm:app for a module’s. The name is the surface’s identity and does not change when its mount path does.

string
navigation
Any of:

Navigation metadata for a surface entry on the wire.

object
icon

A Phosphor icon name for this surface, when set.

string | null
label
required

Display label for this surface in a launcher or navigation menu.

string
order

Sort order relative to other listed surfaces, when set.

integer | null format: int32
unmounted

Surfaces a module declares that are not mounted, with the reason. Present only when the caller can read the owning module’s metadata and at least one such surface exists.

Array<object>

One declared-but-unmounted surface on the wire.

Visible only to a principal who can read the owning module’s metadata: the entry exposes a path on the server’s disk.

object
expectedPath

The path the entry file was expected at. Present for entryMissing.

string | null
key
required

Surface key within the owning module: the second half of name.

string
module
required

Owning module’s qualified key.

string
mountPath
required

The mount path the surface declares. It may change while the surface keeps its name.

string
name
required

Canonical name of the surface, in the same form as the name of a surfaces entry: the owning module’s qualified key, a :, then the surface key, as in acme.crm:app.

string
reason
required

Why the surface is not mounted.

One of:

The server has no surfaces.directory setting.

string
Allowed value: directoryNotConfigured
Example
{
"surfaces": [
{
"kind": "web"
}
],
"unmounted": [
{
"reason": "directoryNotConfigured"
}
]
}

Structured error envelope (SPEC-DATA-0006): {"errors": [{"domain", "scope", "target", "code", "message"}, ...]}. domain (added #950 D9) names the subsystem that produced the entry (data, metadata, apply, git, auth, iam, hfx, or api for a transport-level failure with no domain error behind it) and is always present.

Media typeapplication/json

The top-level response body. Wraps a non-empty list of [ErrorEntry].

object
errors
required

The error entries making up the envelope. Always non-empty.

Array<object>

One entry in the error envelope.

Carries a [Domain] naming the subsystem that produced it, an anchoring [ErrorScope], an optional target that disambiguates within the scope, a stable SCREAMING_SNAKE_CASE code, and a human-readable English message. See SPEC-DATA-0006 for the full envelope contract.

object
code
required

Machine-readable, stable, SCREAMING_SNAKE_CASE identifier.

string
domain
required

Which subsystem produced this entry. Always serialized.

One of:

data::error::DataError – record CRUD, validation, queries.

string
Allowed value: data
location
Any of:

HFX source location for an HFX_PARSE entry.

Emitted as the extra location field on the entry JSON when present. The line/column are 1-based. The frame is the offending source line extracted verbatim from the input.

object
column
required

1-based column within the line, measured in UTF-16 code units of the prefix so browser-side editors can consume it directly.

integer format: uint32
frame

The offending source line text, when available.

string | null
line
required

1-based line number within the source text.

integer format: uint32
message
required

Server-authored English message. Not part of the API contract; may change across releases without notice.

string
rule

The key of the validation rule that failed, when the code is RULE_FAILED. None for all other codes. Skipped during serialization when absent so it does not appear on unrelated entries (same pattern as location).

string | null
scope
required

Anchoring category. Drives client-side rendering.

One of:

Attached to a specific request field. target is the field key.

string
Allowed value: field
target

Field key for field scope, record id for record scope, null otherwise. Always serialized, even when null.

string | null
Example
{
"errors": [
{
"domain": "data",
"scope": "field"
}
]
}