mehendocs

ReferencePlatform API

Platform API#

What does each platform route take and answer, and how is a call signed?

On this page

A platform is a business that serves its own users through Mehen (Platforms and managed workspaces). It calls the vault at https://app.mehen.dev, under /v1/platform, with JSON in and out. Build on Mehen walks through the calls in order; @mehen/client's platform client makes every one of them for you. The tables on this page are generated from the route table in Mehen's protocol, so they say what the vault named in the footer accepts.

Signing a call#

Every call carries a Mehen-Platform-Proof header: a compact JWS, signed with the platform's own P-256 key, over that one request. There is no bearer token, so nothing on the platform's disk or in a log can be replayed.

header  { "alg": "ES256", "typ": "mehen-platform+jwt", "kid": "pky_..." }
payload { "plt": "plt_...", "sub": "<subject>", "htm": "POST", "htu": "https://app.mehen.dev/v1/platform/...", "bh": "<base64url SHA-256 of the body>", "iat": 1793270400, "jti": "<random>" }
ClaimWhat it is
kidThe platform key's id, pky_..., which Mehen's operator gave the platform when it registered the key.
pltThe platform's id, plt_.... It must be the key's own platform.
subThe subject the path names, on every route under /v1/platform/subjects/:subject, and absent on every other route. It must equal the path's subject.
htm, htuThe method, and the full URL with its query.
bhThe base64url SHA-256 of the exact body bytes, or of nothing for a request with no body.
iatWhen it was signed, in seconds. The vault accepts 60 seconds either way.
jtiA random nonce. The vault accepts each one once.

The proof's typ and header differ from a machine's Mehen-Proof, so neither can stand in for the other, and a platform call that also carries Mehen-Proof is refused with bad_request. The vault checks the proof in this order: the key by its id, with no cache; the signature, method, URL, body hash, time and subject; the platform's status; then the nonce, spent once per key, and the platform's limits. Keys, proofs and signing has the details.

Subjects#

A subject is the platform's own name for one of its users: 8 to 128 of A-Z a-z 0-9 _ -. Mehen never interprets it, and it is unique within its platform only: the vault finds a workspace from the verified platform and the subject together, so another platform naming the same string reaches its own workspace or none. Choose a subject that says nothing about the person, and never reuse one.

Answers and refusals#

A success is the JSON the route's table gives. Answers may gain members in later releases; read what you know and ignore the rest. No answer carries a secret value, a client secret, a token, a link to a Mehen page or a command to run.

A refusal is the error object of Errors and exit codes, with the header Mehen-Error: 1 and the HTTP status that page gives its code. Two codes are only ever a platform's: platform_suspended and quota_exceeded.

In a managed workspace, a refusal a machine gets on the ordinary machine routes carries no link: approval_required names the approval and its binding code for the platform to decide, and needs_reauth says the platform reconnects the account. HTTP surfaces lists how each machine route answers there.

Routes#

Every route is under /v1/platform and carries Mehen-Platform-Proof. In the tables below, a nested member such as a.b is required within its parent, a[].b is a member of each item of the array a, and a.<name>.b a member of each value of the map a. The platform's own routes:

RouteMethod and pathWhat it does
platform.viewGET /v1/platformReads the platform as Mehen holds it: its status, limits, defaults and their revision, how many subjects it has, and its keys.
subjects.listGET /v1/platform/subjectsLists the platform's own subjects, a page at a time, with each one's status.
defaults.putPUT /v1/platform/defaultsReplaces the platform's defaults: which templates and providers its users may add, default OAuth scopes and tags, rules added to a template's or provider's policy, and whether keys with no template may be read without a hold.
subjects.removeAllDELETE /v1/platform/subjectsDeletes every subject the platform has, each as deleting one does, 50 at a time.

One subject's routes, each under /v1/platform/subjects/:subject:

RouteMethod and pathWhat it does
subjects.ensurePUT /v1/platform/subjects/:subjectMakes sure the subject has its managed workspace: 201 when it is made, 200 when it already existed.
subjects.getGET /v1/platform/subjects/:subjectReads one subject: its status and how many devices, items and projects its workspace holds.
subjects.removeDELETE /v1/platform/subjects/:subjectDeletes a subject: every device is revoked, every secret and item deleted, and the audit kept until the purge date in the answer, when the whole workspace is erased.
devices.createPOST /v1/platform/subjects/:subject/devicesProvisions a device in the subject's workspace for one of the platform's agents, with no enrolment page.
devices.listGET /v1/platform/subjects/:subject/devicesLists the subject's devices, with when each was last seen and how many live workloads it has.
devices.revokeDELETE /v1/platform/subjects/:subject/devices/:deviceRevokes a device.
items.listGET /v1/platform/subjects/:subject/itemsLists the subject's items by Mehen's metadata (name, kind, provider, account, tags, hosts, status and policy).
items.removeDELETE /v1/platform/subjects/:subject/items/:slugDeletes an item and its secrets.
intakes.createPOST /v1/platform/subjects/:subject/intakesOpens a request for a credential and answers the vault's seal key and the fields to fill in: a key from a catalogue template or for one host, or the person's own OAuth app, for a catalogue provider (with its set-up steps) or with its own provider definition.
intakes.submitPOST /v1/platform/subjects/:subject/intakes/:intake/submitSubmits the sealed values for an open request.
intakes.cancelPOST /v1/platform/subjects/:subject/intakes/:intake/cancelCancels an open request for a credential.
connects.startPOST /v1/platform/subjects/:subject/connectsStarts connecting an account with the person's own OAuth app, held in their workspace, and answers the provider's authorisation URL, carrying Mehen's state, the platform's callback and a PKCE challenge where the provider supports one, for the platform to send the person to.
connects.finishPOST /v1/platform/subjects/:subject/connects/finishFinishes a connection with what the platform's callback received.
connects.getGET /v1/platform/subjects/:subject/connects/:connectReads a connection's progress and outcome.
connects.cancelPOST /v1/platform/subjects/:subject/connects/:connect/cancelCancels a connection that has not finished.
approvals.listGET /v1/platform/subjects/:subject/approvalsLists the subject's held requests, filtered by status.
approvals.getGET /v1/platform/subjects/:subject/approvals/:approvalReads one held request: the exact request it would send, its digest, the device and workload that asked, what Mehen could not read, and who decided it.
approvals.decidePOST /v1/platform/subjects/:subject/approvals/:approval/decideApproves or denies a held request, naming its digest.
projects.createPOST /v1/platform/subjects/:subject/projectsCreates a project, a named set of settings and keys for computers, with its environments.
projects.getGET /v1/platform/subjects/:subject/projects/:projectReads a project and its variables, plain values included.
projects.setVarPUT /v1/platform/subjects/:subject/projects/:project/vars/:nameSets one variable in one environment to a plain value or an item's field, or unsets it when neither is sent.
projects.removeDELETE /v1/platform/subjects/:subject/projects/:projectDeletes a project.
audit.readGET /v1/platform/subjects/:subject/auditReads the subject's audit chain a page at a time, every row, with its head and whether it verified.
workspace.freezePOST /v1/platform/subjects/:subject/freezeFreezes the subject's workspace: nothing is used or changed until it is unfrozen.
workspace.unfreezePOST /v1/platform/subjects/:subject/unfreezeUnfreezes the subject's workspace.

Common refusals#

Any route may answer these, beyond its own. Every refusal is an error object with the header Mehen-Error: 1.

errorWhen
unauthenticatedNo proof, or its key is unknown, revoked, past its rotation date or not this platform's.
proof_invalidThe proof's signature, time, method, URL, body hash or subject does not match the request, or its nonce was used before.
platform_suspendedMehen's operator suspended or retired the platform.
rate_limitedToo many calls or decisions for the platform or the subject; wait retryAfter seconds.
bad_requestThe path, query or body does not have the shape this page gives.
not_foundThe subject, or the object the path names, is not this platform's, exactly as if it did not exist.

Limits#

Mehen's operator sets each platform's limits when it registers the platform, and may change them later. Every managed workspace reads them live; past one, a route answers quota_exceeded or rate_limited. The defaults:

LimitDefaultRangeWhat it limits
subjects1,0001 to 10,000,000How many subjects (users) the platform may have at once, counting those still being deleted.
devicesPerSubject161 to 1,000Live devices in one subject's workspace. A revoked device no longer counts.
itemsPerSubject1001 to 10,000Credentials in one subject's workspace: keys, OAuth apps and connections together.
projectsPerSubject161 to 1,000Projects in one subject's workspace. Each environment holds up to 500 variables, as everywhere in Mehen.
openRequestsPerSubject101 to 100Requests for a credential and connections the platform has started in one subject's workspace and not yet finished or cancelled.
callsPerMinute6001 to 100,000Platform calls a minute, across all of the platform's subjects. A call is counted once its proof is verified; past it, rate_limited.
subjectWritesPerMinute601 to 10,000Calls that change something, a minute, in one subject's workspace.
decisionsPerMinute301 to 10,000Approvals and denials a minute, across all of the platform's subjects.
subjectDecisionsPerMinute101 to 1,000Approvals and denials a minute, in one subject's workspace.
decisionTtlSeconds90060 to 900The longest an approval the platform gives may stay usable, in seconds. An approval always serves one use.
auditRetentionDays300 to 90How long a deleted subject's audit is kept before the whole workspace is erased, in days. Secrets are deleted at once, whatever this says.

The platform#

platform.view#

GET /v1/platform

Reads the platform as Mehen holds it: its status, limits, defaults and their revision, how many subjects it has, and its keys.

Answer (200).

FieldTypeRequired
platformobjectyes
platform.idstring matching ^plt_[A-Za-z0-9_-]{4,64}$yes
platform.slugstring matching ^[a-z][a-z0-9-]{2,39}$yes
platform.namestringyes
platform.statusone of active, suspended, retiring, retiredyes
limitsobjectyes
limits.subjectsinteger, 1 to 10,000,000yes
limits.devicesPerSubjectinteger, 1 to 1,000yes
limits.itemsPerSubjectinteger, 1 to 10,000yes
limits.projectsPerSubjectinteger, 1 to 1,000yes
limits.openRequestsPerSubjectinteger, 1 to 100yes
limits.callsPerMinuteinteger, 1 to 100,000yes
limits.subjectWritesPerMinuteinteger, 1 to 10,000yes
limits.decisionsPerMinuteinteger, 1 to 10,000yes
limits.subjectDecisionsPerMinuteinteger, 1 to 1,000yes
limits.decisionTtlSecondsinteger, 60 to 900yes
limits.auditRetentionDaysinteger, 0 to 90yes
defaultsobjectyes
defaults.templatesarray of string, 1 to 64 characters, at most 256 itemsno
defaults.providersarray of string, 1 to 64 characters, at most 64 itemsno
defaults.scopesmap of keys (string, 1 to 64 characters) to values (array of string, 1 to 200 characters, at most 50 items)yes
defaults.tagsarray of string matching ^[a-z0-9][a-z0-9:_-]{0,39}$, at most 16 itemsyes
defaults.customReadsone of allow, approveyes
defaults.rulesmap of keys (string, 1 to 64 characters) to values (array of object, at most 64 items)yes
defaults.rules.<name>[].actionone of allow, approve, denyyes
defaults.rules.<name>[].methodsarray of string, 1 to 16 characters, at most 16 itemsno
defaults.rules.<name>[].pathsarray of string, at most 256 characters, at most 32 itemsno
defaults.rules.<name>[].bodyone of graphql-mutation, graphql-queryno
defaults.rules.<name>[].notestring, at most 200 charactersno
defaultsRevisioninteger, at least 1yes
usageobjectyes
usage.subjectsintegeryes
keysarray of objectyes
keys[].idstring matching ^pky_[A-Za-z0-9_-]{4,64}$yes
keys[].createdAttime (ISO 8601)yes
keys[].expiresAttime (ISO 8601), or nullyes
keys[].revokedbooleanyes

Its own refusals: none beyond the common ones.

subjects.list#

GET /v1/platform/subjects

Lists the platform's own subjects, a page at a time, with each one's status. Another platform's subjects are never listed.

Query. Every value is a string on the wire.

ParameterTypeRequired
cursorstring, 1 to 256 charactersno

Answer (200).

FieldTypeRequired
subjectsarray of object, at most 100 itemsyes
subjects[].subjectstring matching ^[A-Za-z0-9_-]{8,128}$yes
subjects[].statusone of creating, active, deleting, deletedyes
subjects[].createdAttime (ISO 8601)yes
nextstring, or nullyes

Its own refusals: none beyond the common ones.

defaults.put#

PUT /v1/platform/defaults

Replaces the platform's defaults: which templates and providers its users may add, default OAuth scopes and tags, rules added to a template's or provider's policy, and whether keys with no template may be read without a hold. Rules may only hold or refuse, never allow. Every workspace uses the new defaults within 30 seconds, and approvals made under the old ones go stale.

Body.

FieldTypeRequired
templatesarray of string, 1 to 64 characters, at most 256 itemsno
providersarray of string, 1 to 64 characters, at most 64 itemsno
scopesmap of keys (string, 1 to 64 characters) to values (array of string, 1 to 200 characters, at most 50 items)yes
tagsarray of string matching ^[a-z0-9][a-z0-9:_-]{0,39}$, at most 16 itemsyes
customReadsone of allow, approveyes
rulesmap of keys (string, 1 to 64 characters) to values (array of object, at most 64 items)yes
rules.<name>[].actionone of allow, approve, denyyes
rules.<name>[].methodsarray of string, 1 to 16 characters, at most 16 itemsno
rules.<name>[].pathsarray of string, at most 256 characters, at most 32 itemsno
rules.<name>[].bodyone of graphql-mutation, graphql-queryno
rules.<name>[].notestring, at most 200 charactersno

Answer (200).

FieldTypeRequired
defaultsobjectyes
defaults.templatesarray of string, 1 to 64 characters, at most 256 itemsno
defaults.providersarray of string, 1 to 64 characters, at most 64 itemsno
defaults.scopesmap of keys (string, 1 to 64 characters) to values (array of string, 1 to 200 characters, at most 50 items)yes
defaults.tagsarray of string matching ^[a-z0-9][a-z0-9:_-]{0,39}$, at most 16 itemsyes
defaults.customReadsone of allow, approveyes
defaults.rulesmap of keys (string, 1 to 64 characters) to values (array of object, at most 64 items)yes
defaults.rules.<name>[].actionone of allow, approve, denyyes
defaults.rules.<name>[].methodsarray of string, 1 to 16 characters, at most 16 itemsno
defaults.rules.<name>[].pathsarray of string, at most 256 characters, at most 32 itemsno
defaults.rules.<name>[].bodyone of graphql-mutation, graphql-queryno
defaults.rules.<name>[].notestring, at most 200 charactersno
defaultsRevisioninteger, at least 1yes

Its own refusals: none beyond the common ones.

The table gives a rule's action as the policy shape allows it; a platform's rule may only be approve or deny, and an allow rule is refused with bad_request. So are a template, provider or scope the catalogue lacks, and a tag given twice.

subjects.removeAll#

DELETE /v1/platform/subjects

Deletes every subject the platform has, each as deleting one does, 50 at a time. confirm must be the platform's own slug. The platform stays registered.

Body.

FieldTypeRequired
confirmstring matching ^[a-z][a-z0-9-]{2,39}$yes

Answer (200).

FieldTypeRequired
deletingintegeryes

Its own refusals: none beyond the common ones.

A subject#

Every route here names one subject in its path, and its proof's sub claim must be that same subject. A subject the platform does not have is not_found, exactly as one that never existed.

subjects.ensure#

PUT /v1/platform/subjects/:subject

Makes sure the subject has its managed workspace: 201 when it is made, 200 when it already existed. Refused while the subject is still being deleted, and while the platform is retiring.

Path.

ParameterTypeRequired
subjectstring matching ^[A-Za-z0-9_-]{8,128}$yes

Body. {}

Answer (200 or 201).

FieldTypeRequired
subjectstring matching ^[A-Za-z0-9_-]{8,128}$yes
statusone of creating, active, deleting, deletedyes
createdAttime (ISO 8601)yes
countsobjectyes
counts.devicesintegeryes
counts.itemsintegeryes
counts.projectsintegeryes

Its own refusals, beyond the common ones: quota_exceeded, conflict.

subjects.get#

GET /v1/platform/subjects/:subject

Reads one subject: its status and how many devices, items and projects its workspace holds. A deleted subject is answered until its purge, so its audit can still be read.

Path.

ParameterTypeRequired
subjectstring matching ^[A-Za-z0-9_-]{8,128}$yes

Answer (200).

FieldTypeRequired
subjectstring matching ^[A-Za-z0-9_-]{8,128}$yes
statusone of creating, active, deleting, deletedyes
createdAttime (ISO 8601)yes
countsobjectyes
counts.devicesintegeryes
counts.itemsintegeryes
counts.projectsintegeryes

Its own refusals: none beyond the common ones.

subjects.remove#

DELETE /v1/platform/subjects/:subject

Deletes a subject: every device is revoked, every secret and item deleted, and the audit kept until the purge date in the answer, when the whole workspace is erased. Repeating it answers the same.

Path.

ParameterTypeRequired
subjectstring matching ^[A-Za-z0-9_-]{8,128}$yes

Body. {}

Answer (200).

FieldTypeRequired
subjectstring matching ^[A-Za-z0-9_-]{8,128}$yes
statusdeletedyes
purgeAftertime (ISO 8601)yes

Its own refusals: none beyond the common ones.

devices.create#

POST /v1/platform/subjects/:subject/devices

Provisions a device in the subject's workspace for one of the platform's agents, with no enrolment page. It may only relay and serve placeholders, and acts only through workloads. The same key again answers the existing device with 200.

Path.

ParameterTypeRequired
subjectstring matching ^[A-Za-z0-9_-]{8,128}$yes

Body.

FieldTypeRequired
namestring, 1 to 64 charactersyes
jwkobjectyes
jwk.ktyECyes
jwk.crvP-256yes
jwk.xstring matching ^[A-Za-z0-9_-]{43}$yes
jwk.ystring matching ^[A-Za-z0-9_-]{43}$yes
modesarray of one of relay, placeholder, 1 to 2 itemsyes
labelstring matching ^[A-Za-z0-9_.:-]{1,120}$no

Answer (200 or 201).

FieldTypeRequired
devicestring matching ^dev_[A-Za-z0-9_-]{1,60}$yes
tenantstring matching ^tn_[A-Za-z0-9]{8,40}$yes
namestringyes
labelstring, or nullyes
scopeobjectyes
scope.tagsarray of string matching ^[a-z0-9][a-z0-9:_-]{0,39}$, at most 32 itemsyes
scope.projectsarray of string, 1 to 64 characters, at most 32 itemsyes
scope.maxEnvironmentone of unprotected, protectedyes
scope.modesarray of one of relay, sign, mint, placeholder, lease, 1 to 5 itemsyes
scope.privateCredentialsbooleanyes
scope.workloadsone of allowed, requiredno
createdAttime (ISO 8601)yes
revokedbooleanyes

Its own refusals, beyond the common ones: quota_exceeded, conflict, frozen.

devices.list#

GET /v1/platform/subjects/:subject/devices

Lists the subject's devices, with when each was last seen and how many live workloads it has.

Path.

ParameterTypeRequired
subjectstring matching ^[A-Za-z0-9_-]{8,128}$yes

Answer (200).

FieldTypeRequired
devicesarray of objectyes
devices[].devicestring matching ^dev_[A-Za-z0-9_-]{1,60}$yes
devices[].tenantstring matching ^tn_[A-Za-z0-9]{8,40}$yes
devices[].namestringyes
devices[].labelstring, or nullyes
devices[].scopeobjectyes
devices[].scope.tagsarray of string matching ^[a-z0-9][a-z0-9:_-]{0,39}$, at most 32 itemsyes
devices[].scope.projectsarray of string, 1 to 64 characters, at most 32 itemsyes
devices[].scope.maxEnvironmentone of unprotected, protectedyes
devices[].scope.modesarray of one of relay, sign, mint, placeholder, lease, 1 to 5 itemsyes
devices[].scope.privateCredentialsbooleanyes
devices[].scope.workloadsone of allowed, requiredno
devices[].createdAttime (ISO 8601)yes
devices[].revokedbooleanyes
devices[].lastSeenAttime (ISO 8601), or nullyes
devices[].liveWorkloadsintegeryes

Its own refusals: none beyond the common ones.

devices.revoke#

DELETE /v1/platform/subjects/:subject/devices/:device

Revokes a device. Its workloads, open asks and runs end with it. Repeating it answers the same.

Path.

ParameterTypeRequired
subjectstring matching ^[A-Za-z0-9_-]{8,128}$yes
devicestring matching ^dev_[A-Za-z0-9_-]{1,60}$yes

Answer (200).

FieldTypeRequired
devicestring matching ^dev_[A-Za-z0-9_-]{1,60}$yes
tenantstring matching ^tn_[A-Za-z0-9]{8,40}$yes
namestringyes
labelstring, or nullyes
scopeobjectyes
scope.tagsarray of string matching ^[a-z0-9][a-z0-9:_-]{0,39}$, at most 32 itemsyes
scope.projectsarray of string, 1 to 64 characters, at most 32 itemsyes
scope.maxEnvironmentone of unprotected, protectedyes
scope.modesarray of one of relay, sign, mint, placeholder, lease, 1 to 5 itemsyes
scope.privateCredentialsbooleanyes
scope.workloadsone of allowed, requiredno
createdAttime (ISO 8601)yes
revokedbooleanyes

Its own refusals, beyond the common ones: frozen.

items.list#

GET /v1/platform/subjects/:subject/items

Lists the subject's items by Mehen's metadata (name, kind, provider, account, tags, hosts, status and policy). Never a value.

Path.

ParameterTypeRequired
subjectstring matching ^[A-Za-z0-9_-]{8,128}$yes

Query. Every value is a string on the wire.

ParameterTypeRequired
kindone of api-key, bearer-token, basic-auth, custom-headers, oauth-client, oauth-connection, google-service-account, github-app, hmac-key, ssh-key, password-login, totp, database-url, smtp-imap, cloud-access-key, file, note, genericno
tagstring matching ^[a-z0-9][a-z0-9:_-]{0,39}$no

Answer (200).

FieldTypeRequired
itemsarray of objectyes
items[].slugstring matching ^[a-z][a-z0-9-]{1,63}$yes
items[].kindone of api-key, bearer-token, basic-auth, custom-headers, oauth-client, oauth-connection, google-service-account, github-app, hmac-key, ssh-key, password-login, totp, database-url, smtp-imap, cloud-access-key, file, note, genericyes
items[].providerstring, or nullyes
items[].accountstring, or nullyes
items[].accountVerifiedbooleanyes
items[].tagsarray of stringyes
items[].ceilingone of relay, sign, mint, placeholder, lease, revealyes
items[].hostsarray of stringyes
items[].statusone of active, needs_reauth, refresh_retrying, disabledyes
items[].reviewobjectno
items[].review.reasonstringyes
items[].review.sincestringyes
items[].updatedAtstringyes
items[].lastUsedAtstring, or nullno
items[].policyobjectno
items[].policy.defaultone of allow, approve, denyyes
items[].policy.rulesarray of object, at most 64 itemsyes
items[].policy.rules[].actionone of allow, approve, denyyes
items[].policy.rules[].methodsarray of string, 1 to 16 characters, at most 16 itemsno
items[].policy.rules[].pathsarray of string, at most 256 characters, at most 32 itemsno
items[].policy.rules[].bodyone of graphql-mutation, graphql-queryno
items[].policy.rules[].notestring, at most 200 charactersno

Its own refusals: none beyond the common ones.

items.remove#

DELETE /v1/platform/subjects/:subject/items/:slug

Deletes an item and its secrets. Approvals and grants on it end. An OAuth connection's token is handed back to the provider first where the provider allows it.

Path.

ParameterTypeRequired
subjectstring matching ^[A-Za-z0-9_-]{8,128}$yes
slugstring matching ^[a-z][a-z0-9-]{1,63}$yes

Answer (200).

FieldTypeRequired
slugstring matching ^[a-z][a-z0-9-]{1,63}$yes
deletedtrueyes
providerRevokedbooleanyes

Its own refusals, beyond the common ones: frozen.

intakes.create#

POST /v1/platform/subjects/:subject/intakes

Opens a request for a credential and answers the vault's seal key and the fields to fill in: a key from a catalogue template or for one host, or the person's own OAuth app, for a catalogue provider (with its set-up steps) or with its own provider definition. The person types the values into the platform's own page, which seals each secret in their browser before it reaches the platform. An existing name of the same kind is a rotation and keeps where the key may go. It lives 10 minutes and carries no link.

Path.

ParameterTypeRequired
subjectstring matching ^[A-Za-z0-9_-]{8,128}$yes

Body.

FieldTypeRequired
slugstring matching ^[a-z][a-z0-9-]{1,63}$yes
serviceobject, one of 3 shapesyes
service.templatestring, 1 to 64 charactersin its shape
service.hoststringin its shape
service.customProviderobjectin its shape
service.customProvider.namestring, 1 to 64 charactersyes
service.customProvider.authorizeUrlURL, at most 2048 charactersyes
service.customProvider.tokenUrlURL, at most 2048 charactersyes
service.customProvider.scopesarray of string matching ^[\x21\x23-\x2B\x2D-\x5B\x5D-\x7E]{1,200}$, at most 50 itemsyes
service.customProvider.scopeSeparatorone of " ", ,no
service.customProvider.pkceone of S256, noneyes
service.customProvider.clientAuthone of client_secret_post, client_secret_basic, noneyes
service.customProvider.authorizeParamsmap of keys (string matching ^[A-Za-z0-9_.-]{1,64}$) to values (string, at most 200 characters)no
service.customProvider.hostsarray of string, 1 to 16 itemsyes
service.customProvider.injectionobject, one of 2 shapesno
service.customProvider.injection.inheader or queryyes
service.customProvider.injection.namestring matching ^[A-Za-z0-9-]{1,64}$ or string matching ^[A-Za-z0-9_.-]{1,64}$yes
service.customProvider.injection.formatstring, 1 to 200 charactersin its shape
service.customProvider.injection.fieldaccess_tokenin its shape
tagsarray of string matching ^[a-z0-9][a-z0-9:_-]{0,39}$, at most 16 itemsno
reasonstring, 1 to 500 charactersno

Answer (201).

FieldTypeRequired
intakestring matching ^int_[A-Za-z0-9_-]{1,60}$yes
sealKeyobjectyes
sealKey.jwkobjectyes
sealKey.jwk.ktyECyes
sealKey.jwk.crvP-256yes
sealKey.jwk.xstringyes
sealKey.jwk.ystringyes
sealKey.kidstringyes
fieldsarray of objectyes
fields[].namestring matching ^[a-z][a-z0-9_]{0,63}$yes
fields[].labelstringyes
fields[].secretbooleanyes
fields[].requiredbooleanyes
fields[].multilinebooleanyes
fields[].hintstring, or nullyes
bindingobjectyes
binding.hostsarray of stringyes
binding.knownbooleanyes
rotatesbooleanyes
setuparray of object, or nullyes
setup[].titlestring, 1 to 80 charactersyes
setup[].bodystring, 1 to 400 charactersyes
setup[].consoleUrlURLno
expiresAttime (ISO 8601)yes

Its own refusals, beyond the common ones: conflict, quota_exceeded, frozen.

service is one of three shapes. { template } names a catalogue template: a key's, or a provider's app template such as google-oauth-client, whose answer carries the template's set-up steps in setup, each body possibly holding {callback} for the platform's page to replace with its own callback URL. { host } is a key for one API host with no template; every request with it is held unless the platform's customReads lets reads through. { customProvider } is the user's own OAuth app with its own provider definition: authorizeUrl and tokenUrl are https on a public host name, with no user name, password or fragment, and never an IP address or a private name; authorizeParams holds at most 8 names, none that Mehen sets itself; each scope and host appears once. The shape allows clientAuth: "none", a public app with no secret, but the vault does not support one yet and refuses its intake with bad_request. The definition is fixed with the app, and the app's client secret is bound to the token URL's host and path, by POST, so it is sent nowhere else. A template outside the platform's templates default is bad_request. A slug the user already has is a rotation of that credential: of another kind or service it is conflict, and so is a different definition under an existing app's name.

intakes.submit#

POST /v1/platform/subjects/:subject/intakes/:intake/submit

Submits the sealed values for an open request. Each box opens only for this request and field, and only once. The name, where the key may go, its tags and its home are the request's, never the body's.

Path.

ParameterTypeRequired
subjectstring matching ^[A-Za-z0-9_-]{8,128}$yes
intakestring matching ^int_[A-Za-z0-9_-]{1,60}$yes

Body.

FieldTypeRequired
sealedmap of keys (string matching ^[a-z][a-z0-9_]{0,63}$) to values (object)yes
sealed.<name>.v1yes
sealed.<name>.epkobjectyes
sealed.<name>.epk.ktyECyes
sealed.<name>.epk.crvP-256yes
sealed.<name>.epk.xstring matching ^[A-Za-z0-9_-]{43}$yes
sealed.<name>.epk.ystring matching ^[A-Za-z0-9_-]{43}$yes
sealed.<name>.ivstring matching ^[A-Za-z0-9_-]{16}$yes
sealed.<name>.ctstring matching ^[A-Za-z0-9_-]+$yes
publicFieldsmap of keys (string matching ^[a-z][a-z0-9_]{0,63}$) to values (string, at most 4,096 characters)no

Answer (200).

FieldTypeRequired
itemobjectyes
item.slugstring matching ^[a-z][a-z0-9-]{1,63}$yes
item.kindone of api-key, bearer-token, basic-auth, custom-headers, oauth-client, oauth-connection, google-service-account, github-app, hmac-key, ssh-key, password-login, totp, database-url, smtp-imap, cloud-access-key, file, note, genericyes
item.providerstring, or nullyes
item.accountstring, or nullyes
item.accountVerifiedbooleanyes
item.tagsarray of stringyes
item.ceilingone of relay, sign, mint, placeholder, lease, revealyes
item.hostsarray of stringyes
item.statusone of active, needs_reauth, refresh_retrying, disabledyes
item.reviewobjectno
item.review.reasonstringyes
item.review.sincestringyes
item.updatedAtstringyes
item.lastUsedAtstring, or nullno
item.policyobjectno
item.policy.defaultone of allow, approve, denyyes
item.policy.rulesarray of object, at most 64 itemsyes
item.policy.rules[].actionone of allow, approve, denyyes
item.policy.rules[].methodsarray of string, 1 to 16 characters, at most 16 itemsno
item.policy.rules[].pathsarray of string, at most 256 characters, at most 32 itemsno
item.policy.rules[].bodyone of graphql-mutation, graphql-queryno
item.policy.rules[].notestring, at most 200 charactersno

Its own refusals, beyond the common ones: conflict, quota_exceeded, frozen.

Seal each field the intake marked secret under intake/<intake>/<field>, and send the others, such as an OAuth app's client_id, in publicFields.

intakes.cancel#

POST /v1/platform/subjects/:subject/intakes/:intake/cancel

Cancels an open request for a credential.

Path.

ParameterTypeRequired
subjectstring matching ^[A-Za-z0-9_-]{8,128}$yes
intakestring matching ^int_[A-Za-z0-9_-]{1,60}$yes

Body. {}

Answer (200). {}

Its own refusals: none beyond the common ones.

connects.start#

POST /v1/platform/subjects/:subject/connects

Starts connecting an account with the person's own OAuth app, held in their workspace, and answers the provider's authorisation URL, carrying Mehen's state, the platform's callback and a PKCE challenge where the provider supports one, for the platform to send the person to. Without scopes it asks for the platform's default scopes for a catalogue provider, else the catalogue's, or every scope of the app's own provider definition. It lives 15 minutes.

Path.

ParameterTypeRequired
subjectstring matching ^[A-Za-z0-9_-]{8,128}$yes

Body.

FieldTypeRequired
providerstring, 1 to 64 charactersno
clientstring matching ^[a-z][a-z0-9-]{1,63}$no
slugstring matching ^[a-z][a-z0-9-]{1,63}$yes
redirectUriURL, at most 2048 charactersyes
scopesarray of string, 1 to 200 characters, 1 to 50 itemsno
expectstring, 1 to 320 charactersno
tagsarray of string matching ^[a-z0-9][a-z0-9:_-]{0,39}$, at most 16 itemsno

Answer (201).

FieldTypeRequired
connectstring matching ^con_[A-Za-z0-9_-]{1,60}$yes
authorizeUrlURLyes
expiresAttime (ISO 8601)yes

Its own refusals, beyond the common ones: conflict, quota_exceeded, frozen.

Name a catalogue provider, and optionally the client, the user's app for it (by default the app named after the provider's app template, such as google-oauth-client); or name only the client, an app with its own provider definition. redirectUri is the platform's own callback, exactly as the user registered it in their app. A provider outside the platform's providers default is bad_request. An existing connection's slug is a reconnect: for a catalogue provider, pinned to the same account at the provider; for an app with its own definition, through the same app. A device's own POST /v1/connect is refused with forbidden in a managed workspace: connections start here.

connects.finish#

POST /v1/platform/subjects/:subject/connects/finish

Finishes a connection with what the platform's callback received. Mehen exchanges the code with the app's client secret, which only Mehen holds, and its own PKCE verifier where it sent a challenge, so the code is useless to anyone else. A state that is not this subject's is not found; a state already used or expired is a conflict.

Path.

ParameterTypeRequired
subjectstring matching ^[A-Za-z0-9_-]{8,128}$yes

Body.

FieldTypeRequired
statestring, 16 to 256 charactersyes
codestring, 1 to 4,096 charactersno
errorstring, 1 to 256 charactersno

Answer (200).

FieldTypeRequired
connectstring matching ^con_[A-Za-z0-9_-]{1,60}$yes
statuscompleted or failedyes
itemobjectin its shape
item.slugstring matching ^[a-z][a-z0-9-]{1,63}$yes
item.kindone of api-key, bearer-token, basic-auth, custom-headers, oauth-client, oauth-connection, google-service-account, github-app, hmac-key, ssh-key, password-login, totp, database-url, smtp-imap, cloud-access-key, file, note, genericyes
item.providerstring, or nullyes
item.accountstring, or nullyes
item.accountVerifiedbooleanyes
item.tagsarray of stringyes
item.ceilingone of relay, sign, mint, placeholder, lease, revealyes
item.hostsarray of stringyes
item.statusone of active, needs_reauth, refresh_retrying, disabledyes
item.reviewobjectno
item.review.reasonstringyes
item.review.sincestringyes
item.updatedAtstringyes
item.lastUsedAtstring, or nullno
item.policyobjectno
item.policy.defaultone of allow, approve, denyyes
item.policy.rulesarray of object, at most 64 itemsyes
item.policy.rules[].actionone of allow, approve, denyyes
item.policy.rules[].methodsarray of string, 1 to 16 characters, at most 16 itemsno
item.policy.rules[].pathsarray of string, at most 256 characters, at most 32 itemsno
item.policy.rules[].bodyone of graphql-mutation, graphql-queryno
item.policy.rules[].notestring, at most 200 charactersno
reasonone of denied, provider, mismatch, widerin its shape

Its own refusals, beyond the common ones: conflict, quota_exceeded, upstream_failed, frozen.

Send the state and either the code or the provider's error from the callback, never both. Name the subject who is signed in to the platform at the callback, not the one the platform expects. A completed connection made with a catalogue provider names the account the provider verified; one made with an app's own definition names none.

connects.get#

GET /v1/platform/subjects/:subject/connects/:connect

Reads a connection's progress and outcome.

Path.

ParameterTypeRequired
subjectstring matching ^[A-Za-z0-9_-]{8,128}$yes
connectstring matching ^con_[A-Za-z0-9_-]{1,60}$yes

Answer (200).

FieldTypeRequired
connectstring matching ^con_[A-Za-z0-9_-]{1,60}$yes
statusone of open, completed, mismatch, failed, expiredyes
itemobjectno
item.slugstring matching ^[a-z][a-z0-9-]{1,63}$yes
item.kindone of api-key, bearer-token, basic-auth, custom-headers, oauth-client, oauth-connection, google-service-account, github-app, hmac-key, ssh-key, password-login, totp, database-url, smtp-imap, cloud-access-key, file, note, genericyes
item.providerstring, or nullyes
item.accountstring, or nullyes
item.accountVerifiedbooleanyes
item.tagsarray of stringyes
item.ceilingone of relay, sign, mint, placeholder, lease, revealyes
item.hostsarray of stringyes
item.statusone of active, needs_reauth, refresh_retrying, disabledyes
item.reviewobjectno
item.review.reasonstringyes
item.review.sincestringyes
item.updatedAtstringyes
item.lastUsedAtstring, or nullno
item.policyobjectno
item.policy.defaultone of allow, approve, denyyes
item.policy.rulesarray of object, at most 64 itemsyes
item.policy.rules[].actionone of allow, approve, denyyes
item.policy.rules[].methodsarray of string, 1 to 16 characters, at most 16 itemsno
item.policy.rules[].pathsarray of string, at most 256 characters, at most 32 itemsno
item.policy.rules[].bodyone of graphql-mutation, graphql-queryno
item.policy.rules[].notestring, at most 200 charactersno
accountstringno
grantedScopesarray of stringno
messagestringno
expiresAttime (ISO 8601)yes

Its own refusals: none beyond the common ones.

connects.cancel#

POST /v1/platform/subjects/:subject/connects/:connect/cancel

Cancels a connection that has not finished.

Path.

ParameterTypeRequired
subjectstring matching ^[A-Za-z0-9_-]{8,128}$yes
connectstring matching ^con_[A-Za-z0-9_-]{1,60}$yes

Body. {}

Answer (200). {}

Its own refusals: none beyond the common ones.

approvals.list#

GET /v1/platform/subjects/:subject/approvals

Lists the subject's held requests, filtered by status.

Path.

ParameterTypeRequired
subjectstring matching ^[A-Za-z0-9_-]{8,128}$yes

Query. Every value is a string on the wire.

ParameterTypeRequired
statusone of pending, approved, denied, expired, used, ended, revoked, staleno

Answer (200).

FieldTypeRequired
approvalsarray of objectyes
approvals[].approvalstring matching ^apr_[A-Za-z0-9_-]{1,60}$yes
approvals[].statusone of pending, approved, denied, expired, used, ended, revoked, staleyes
approvals[].digeststringyes
approvals[].devicestring matching ^dev_[A-Za-z0-9_-]{1,60}$yes
approvals[].workloadobject, or nullyes
approvals[].workload.idstring matching ^wl_[A-Za-z0-9_-]{8,64}$yes
approvals[].workload.labelstringyes
approvals[].itemstring matching ^[a-z][a-z0-9-]{1,63}$yes
approvals[].requestobjectyes
approvals[].request.methodstringyes
approvals[].request.urlstringyes
approvals[].request.contentTypestring, or nullyes
approvals[].request.contentEncodingstring, or nullyes
approvals[].request.headersSha256stringyes
approvals[].request.bodySha256stringyes
approvals[].titlestringyes
approvals[].warningsarray of stringyes
approvals[].constraintsobjectyes
approvals[].constraints.usesinteger, at least 1, or nullyes
approvals[].constraints.ttlSecondsinteger, at least 1yes
approvals[].expiresAttime (ISO 8601)yes
approvals[].decidedByobject, or nullyes
approvals[].decidedBy.platformstring matching ^plt_[A-Za-z0-9_-]{4,64}$yes
approvals[].decidedBy.keystring matching ^pky_[A-Za-z0-9_-]{4,64}$yes
approvals[].decidedBy.refstring matching ^[A-Za-z0-9_.:-]{1,64}$, or nullyes

Its own refusals: none beyond the common ones.

approvals.get#

GET /v1/platform/subjects/:subject/approvals/:approval

Reads one held request: the exact request it would send, its digest, the device and workload that asked, what Mehen could not read, and who decided it.

Path.

ParameterTypeRequired
subjectstring matching ^[A-Za-z0-9_-]{8,128}$yes
approvalstring matching ^apr_[A-Za-z0-9_-]{1,60}$yes

Answer (200).

FieldTypeRequired
approvalstring matching ^apr_[A-Za-z0-9_-]{1,60}$yes
statusone of pending, approved, denied, expired, used, ended, revoked, staleyes
digeststringyes
devicestring matching ^dev_[A-Za-z0-9_-]{1,60}$yes
workloadobject, or nullyes
workload.idstring matching ^wl_[A-Za-z0-9_-]{8,64}$yes
workload.labelstringyes
itemstring matching ^[a-z][a-z0-9-]{1,63}$yes
requestobjectyes
request.methodstringyes
request.urlstringyes
request.contentTypestring, or nullyes
request.contentEncodingstring, or nullyes
request.headersSha256stringyes
request.bodySha256stringyes
titlestringyes
warningsarray of stringyes
constraintsobjectyes
constraints.usesinteger, at least 1, or nullyes
constraints.ttlSecondsinteger, at least 1yes
expiresAttime (ISO 8601)yes
decidedByobject, or nullyes
decidedBy.platformstring matching ^plt_[A-Za-z0-9_-]{4,64}$yes
decidedBy.keystring matching ^pky_[A-Za-z0-9_-]{4,64}$yes
decidedBy.refstring matching ^[A-Za-z0-9_.:-]{1,64}$, or nullyes

Its own refusals: none beyond the common ones.

approvals.decide#

POST /v1/platform/subjects/:subject/approvals/:approval/decide

Approves or denies a held request, naming its digest. An approval is good for one use of that exact request by the workload that asked, for at most the platform's decision limit (15 minutes at most). A digest that is not the request's, or a request no longer pending, is a conflict: the request changed, ask again.

Path.

ParameterTypeRequired
subjectstring matching ^[A-Za-z0-9_-]{8,128}$yes
approvalstring matching ^apr_[A-Za-z0-9_-]{1,60}$yes

Body.

FieldTypeRequired
decisionone of approve, denyyes
digeststring matching ^[A-Za-z0-9_-]{43}$yes
ttlSecondsinteger, 60 to 900no
refstring matching ^[A-Za-z0-9_.:-]{1,64}$no

Answer (200).

FieldTypeRequired
approvalstring matching ^apr_[A-Za-z0-9_-]{1,60}$yes
statusone of pending, approved, denied, expired, used, ended, revoked, staleyes
digeststringyes
devicestring matching ^dev_[A-Za-z0-9_-]{1,60}$yes
workloadobject, or nullyes
workload.idstring matching ^wl_[A-Za-z0-9_-]{8,64}$yes
workload.labelstringyes
itemstring matching ^[a-z][a-z0-9-]{1,63}$yes
requestobjectyes
request.methodstringyes
request.urlstringyes
request.contentTypestring, or nullyes
request.contentEncodingstring, or nullyes
request.headersSha256stringyes
request.bodySha256stringyes
titlestringyes
warningsarray of stringyes
constraintsobjectyes
constraints.usesinteger, at least 1, or nullyes
constraints.ttlSecondsinteger, at least 1yes
expiresAttime (ISO 8601)yes
decidedByobject, or nullyes
decidedBy.platformstring matching ^plt_[A-Za-z0-9_-]{4,64}$yes
decidedBy.keystring matching ^pky_[A-Za-z0-9_-]{4,64}$yes
decidedBy.refstring matching ^[A-Za-z0-9_.:-]{1,64}$, or nullyes

Its own refusals, beyond the common ones: conflict, frozen.

projects.create#

POST /v1/platform/subjects/:subject/projects

Creates a project, a named set of settings and keys for computers, with its environments. Every environment is unprotected. The same name again, with the same environments and default environment, answers the existing project with 200; the same name with other environments or another default environment is a conflict.

Path.

ParameterTypeRequired
subjectstring matching ^[A-Za-z0-9_-]{8,128}$yes

Body.

FieldTypeRequired
slugstring matching ^[a-z][a-z0-9-]{1,63}$yes
environmentsarray of object, 1 to 16 itemsyes
environments[].namestring matching ^[a-z][a-z0-9-]{0,31}$yes
defaultEnvstring matching ^[a-z][a-z0-9-]{0,31}$yes

Answer (200 or 201).

FieldTypeRequired
idstring matching ^prj_[A-Za-z0-9_-]{1,60}$yes
slugstring matching ^[a-z][a-z0-9-]{1,63}$yes
defaultEnvstring matching ^[a-z][a-z0-9-]{0,31}$yes
environmentsarray of objectyes
environments[].namestring matching ^[a-z][a-z0-9-]{0,31}$yes
varsarray of objectyes
vars[].namestring matching ^[A-Za-z_][A-Za-z0-9_]{0,127}$yes
vars[].envstring matching ^[a-z][a-z0-9-]{0,31}$yes
vars[].sourceone of plain, item, unsetyes
vars[].valuestringno
vars[].itemstring matching ^[a-z][a-z0-9-]{1,63}$no
vars[].fieldstring, or nullno

Its own refusals, beyond the common ones: conflict, quota_exceeded, frozen.

projects.get#

GET /v1/platform/subjects/:subject/projects/:project

Reads a project and its variables, plain values included.

Path.

ParameterTypeRequired
subjectstring matching ^[A-Za-z0-9_-]{8,128}$yes
projectstring matching ^prj_[A-Za-z0-9_-]{1,60}$yes

Answer (200).

FieldTypeRequired
idstring matching ^prj_[A-Za-z0-9_-]{1,60}$yes
slugstring matching ^[a-z][a-z0-9-]{1,63}$yes
defaultEnvstring matching ^[a-z][a-z0-9-]{0,31}$yes
environmentsarray of objectyes
environments[].namestring matching ^[a-z][a-z0-9-]{0,31}$yes
varsarray of objectyes
vars[].namestring matching ^[A-Za-z_][A-Za-z0-9_]{0,127}$yes
vars[].envstring matching ^[a-z][a-z0-9-]{0,31}$yes
vars[].sourceone of plain, item, unsetyes
vars[].valuestringno
vars[].itemstring matching ^[a-z][a-z0-9-]{1,63}$no
vars[].fieldstring, or nullno

Its own refusals: none beyond the common ones.

projects.setVar#

PUT /v1/platform/subjects/:subject/projects/:project/vars/:name

Sets one variable in one environment to a plain value or an item's field, or unsets it when neither is sent. before is the value last read; a stale one is a conflict. A plain value that looks like a secret is refused.

Path.

ParameterTypeRequired
subjectstring matching ^[A-Za-z0-9_-]{8,128}$yes
projectstring matching ^prj_[A-Za-z0-9_-]{1,60}$yes
namestring matching ^[A-Za-z_][A-Za-z0-9_]{0,127}$yes

Body.

FieldTypeRequired
envstring matching ^[a-z][a-z0-9-]{0,31}$yes
beforeobject, one of 2 shapes, or nullyes
before.plainstring, at most 4,096 charactersin its shape
before.itemstring matching ^[a-z][a-z0-9-]{1,63}$in its shape
before.fieldstring matching ^[a-z][a-z0-9_]{0,63}$, or nullin its shape
plainstring, at most 4,096 charactersno
itemstring matching ^[a-z][a-z0-9-]{1,63}$no
fieldstring matching ^[a-z][a-z0-9_]{0,63}$no

Answer (200).

FieldTypeRequired
idstring matching ^prj_[A-Za-z0-9_-]{1,60}$yes
slugstring matching ^[a-z][a-z0-9-]{1,63}$yes
defaultEnvstring matching ^[a-z][a-z0-9-]{0,31}$yes
environmentsarray of objectyes
environments[].namestring matching ^[a-z][a-z0-9-]{0,31}$yes
varsarray of objectyes
vars[].namestring matching ^[A-Za-z_][A-Za-z0-9_]{0,127}$yes
vars[].envstring matching ^[a-z][a-z0-9-]{0,31}$yes
vars[].sourceone of plain, item, unsetyes
vars[].valuestringno
vars[].itemstring matching ^[a-z][a-z0-9-]{1,63}$no
vars[].fieldstring, or nullno

Its own refusals, beyond the common ones: conflict, frozen.

projects.remove#

DELETE /v1/platform/subjects/:subject/projects/:project

Deletes a project. Its runs and their placeholders end.

Path.

ParameterTypeRequired
subjectstring matching ^[A-Za-z0-9_-]{8,128}$yes
projectstring matching ^prj_[A-Za-z0-9_-]{1,60}$yes

Body. {}

Answer (200).

FieldTypeRequired
deletedtrueyes

Its own refusals, beyond the common ones: frozen.

audit.read#

GET /v1/platform/subjects/:subject/audit

Reads the subject's audit chain a page at a time, every row, with its head and whether it verified. Every row names the platform.

Path.

ParameterTypeRequired
subjectstring matching ^[A-Za-z0-9_-]{8,128}$yes

Query. Every value is a string on the wire.

ParameterTypeRequired
cursorstring matching ^[1-9][0-9]*$no
limitinteger, 1 to 200no

Answer (200).

FieldTypeRequired
eventsarray of objectyes
events[].seqinteger, at least 1yes
events[].atintegeryes
events[].actorstringyes
events[].actionstringyes
events[].targetstring, or nullyes
events[].detailstringyes
events[].prevstringyes
events[].hashstringyes
verifiedbooleanyes
nextstring matching ^[1-9][0-9]*$, or nullyes
filteredbooleanyes
headobject, or nullyes
head.seqinteger, at least 1yes
head.hashstringyes

Its own refusals: none beyond the common ones.

workspace.freeze#

POST /v1/platform/subjects/:subject/freeze

Freezes the subject's workspace: nothing is used or changed until it is unfrozen.

Path.

ParameterTypeRequired
subjectstring matching ^[A-Za-z0-9_-]{8,128}$yes

Body. {}

Answer (200).

FieldTypeRequired
frozentrueyes

Its own refusals: none beyond the common ones.

workspace.unfreeze#

POST /v1/platform/subjects/:subject/unfreeze

Unfreezes the subject's workspace.

Path.

ParameterTypeRequired
subjectstring matching ^[A-Za-z0-9_-]{8,128}$yes

Body. {}

Answer (200).

FieldTypeRequired
frozenfalseyes

Its own refusals: none beyond the common ones.