API reference
Waitlist and access API
Invite-only access: the form service's sign-up hook, and for the people who run the service, the waitlist and access grants. Operator routes need the operator token.
- Receive a waitlist sign-up:
POST /v1/waitlist/tally - List waitlist entries (operators):
GET /v1/operator/waitlist - Approve a waitlist entry (operators):
POST /v1/operator/waitlist/{entry_id}/approve - Reject a waitlist entry (operators):
POST /v1/operator/waitlist/{entry_id}/reject - Revoke a waitlist entry (operators):
POST /v1/operator/waitlist/{entry_id}/revoke - List access grants (operators):
GET /v1/operator/access-grants - Grant access (operators):
POST /v1/operator/access-grants - Revoke an access grant (operators):
POST /v1/operator/access-grants/{grant_id}/revoke
Receive a waitlist sign-up
POST /v1/waitlist/tally
Accept a waitlist sign-up from the form service (Tally). The raw body
must carry a valid Tally-Signature (base64 HMAC-SHA256 under the
configured signing secret); unsigned or mis-signed requests are refused.
Events other than FORM_RESPONSE are acknowledged and ignored. A second
sign-up from the same address refreshes its answers.
- Authentication: none on this route.
- Who: The form service (signed request).
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
Tally-Signature | header | string | Yes | Base64 HMAC-SHA256 of the raw body under the waitlist signing secret |
Request body (application/json)
No fields.
Responses
| Status | Description | Body |
|---|---|---|
200 | — | WaitlistAckDto |
401 | invalid_signature: missing or wrong signature | ProblemDetails |
404 | the waitlist webhook is not configured | ProblemDetails |
422 | the event has no valid email answer | ProblemDetails |
curl -X POST "$VMYARD_API_URL/v1/waitlist/tally" \
-H "Tally-Signature: $TALLY_SIGNATURE" \
-H "Content-Type: application/json" \
-d '"string"'{
"received": false
}List waitlist entries (operators)
GET /v1/operator/waitlist
Waitlist entries, newest first.
- Authentication: none on this route.
- Who: Service operators (operator token).
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
status | query | WaitlistFilterDto | No | pending (default), approved, rejected, revoked, or all. |
limit | query | integer | No | 1-500, default 100; newest first. |
X-VMYard-Operator-Token | header | string | Yes | Operator token from the service configuration |
Responses
| Status | Description | Body |
|---|---|---|
200 | — | WaitlistPage |
401 | Not signed in, or the API key is malformed, expired, or revoked (unauthenticated, invalid_api_key). | ProblemDetails |
404 | operator access is not configured | ProblemDetails |
curl "$VMYARD_API_URL/v1/operator/waitlist" \
-H "X-VMYard-Operator-Token: $X_VMYARD_OPERATOR_TOKEN"{
"items": [
{
"access_grant_id": "6f1c2d3e-4b5a-4c7d-8e9f-0a1b2c3d4e5f",
"company": "string",
"created_at": "string",
"decided_at": "string",
"decided_by": "string",
"decision_reason": "string",
"email": "ada@example.com",
"id": "6f1c2d3e-4b5a-4c7d-8e9f-0a1b2c3d4e5f",
"name": "dev",
"raw_answers": {},
"status": "pending",
"updated_at": "string",
"use_case": "string"
}
]
}Approve a waitlist entry (operators)
POST /v1/operator/waitlist/{entry_id}/approve
Approve an entry: its email gets an access grant (with the initial credit), and the "you're in" email is sent. Approving an approved entry changes nothing; a rejected or revoked entry may be approved again.
- Authentication: none on this route.
- Who: Service operators (operator token).
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
entry_id | path | string (uuid) | Yes | |
X-VMYard-Operator-Token | header | string | Yes | Operator token from the service configuration |
Request body (application/json, ApproveWaitlistRequest)
| Field | Type | Required | Description |
|---|---|---|---|
operator | string | Yes | The individual operator acting, 1-200 characters. |
initial_credit_micros | integer | null | No | Credits from VMYard granted once to the person's own organization (now if they already signed in, else at their first sign-in). Defaults to the service's access.initial_credit_micros; 0 grants none. |
notify | boolean | null | No | Send the "you're in" email (default true). |
reason | string | null | No | Why, 1-500 characters; optional. |
Responses
| Status | Description | Body |
|---|---|---|
200 | — | WaitlistDecisionDto |
401 | Not signed in, or the API key is malformed, expired, or revoked (unauthenticated, invalid_api_key). | ProblemDetails |
404 | operator access is not configured or the entry is unknown | ProblemDetails |
422 | Invalid request (invalid_request); field_errors names the fields. | ProblemDetails |
curl -X POST "$VMYARD_API_URL/v1/operator/waitlist/$ENTRY_ID/approve" \
-H "X-VMYard-Operator-Token: $X_VMYARD_OPERATOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"operator": "string"
}'{
"changed": false,
"entry": {
"access_grant_id": "6f1c2d3e-4b5a-4c7d-8e9f-0a1b2c3d4e5f",
"company": "string",
"created_at": "string",
"decided_at": "string",
"decided_by": "string",
"decision_reason": "string",
"email": "ada@example.com",
"id": "6f1c2d3e-4b5a-4c7d-8e9f-0a1b2c3d4e5f",
"name": "dev",
"raw_answers": {},
"status": "pending",
"updated_at": "string",
"use_case": "string"
},
"grant": {
"created_at": "string",
"credited_at": "string",
"credited_organization_id": "6f1c2d3e-4b5a-4c7d-8e9f-0a1b2c3d4e5f",
"email": "ada@example.com",
"granted_by": "string",
"id": "6f1c2d3e-4b5a-4c7d-8e9f-0a1b2c3d4e5f",
"initial_credit_micros": 0,
"provider": "github",
"reason": "string",
"revoke_reason": "string",
"revoked_at": "string",
"revoked_by": "string",
"subject": "string"
},
"notification": "sent"
}Reject a waitlist entry (operators)
POST /v1/operator/waitlist/{entry_id}/reject
Reject a pending entry. Rejecting a rejected entry changes nothing; an
approved entry is revoked instead (409 waitlist_decision_conflict).
- Authentication: none on this route.
- Who: Service operators (operator token).
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
entry_id | path | string (uuid) | Yes | |
X-VMYard-Operator-Token | header | string | Yes | Operator token from the service configuration |
Request body (application/json, WaitlistDecisionRequest)
| Field | Type | Required | Description |
|---|---|---|---|
operator | string | Yes | The individual operator acting, 1-200 characters. |
reason | string | Yes | Why, 1-500 characters. |
Responses
| Status | Description | Body |
|---|---|---|
200 | — | WaitlistDecisionDto |
401 | Not signed in, or the API key is malformed, expired, or revoked (unauthenticated, invalid_api_key). | ProblemDetails |
404 | operator access is not configured or the entry is unknown | ProblemDetails |
409 | waitlist_decision_conflict | ProblemDetails |
422 | Invalid request (invalid_request); field_errors names the fields. | ProblemDetails |
curl -X POST "$VMYARD_API_URL/v1/operator/waitlist/$ENTRY_ID/reject" \
-H "X-VMYard-Operator-Token: $X_VMYARD_OPERATOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"operator": "string",
"reason": "string"
}'{
"changed": false,
"entry": {
"access_grant_id": "6f1c2d3e-4b5a-4c7d-8e9f-0a1b2c3d4e5f",
"company": "string",
"created_at": "string",
"decided_at": "string",
"decided_by": "string",
"decision_reason": "string",
"email": "ada@example.com",
"id": "6f1c2d3e-4b5a-4c7d-8e9f-0a1b2c3d4e5f",
"name": "dev",
"raw_answers": {},
"status": "pending",
"updated_at": "string",
"use_case": "string"
},
"grant": {
"created_at": "string",
"credited_at": "string",
"credited_organization_id": "6f1c2d3e-4b5a-4c7d-8e9f-0a1b2c3d4e5f",
"email": "ada@example.com",
"granted_by": "string",
"id": "6f1c2d3e-4b5a-4c7d-8e9f-0a1b2c3d4e5f",
"initial_credit_micros": 0,
"provider": "github",
"reason": "string",
"revoke_reason": "string",
"revoked_at": "string",
"revoked_by": "string",
"subject": "string"
},
"notification": "sent"
}Revoke a waitlist entry (operators)
POST /v1/operator/waitlist/{entry_id}/revoke
Revoke an approved entry: its grant is revoked, so the person (and the organizations only they approve) can no longer create organizations, machines, or API keys. Running machines keep running; suspend the organization to stop them.
- Authentication: none on this route.
- Who: Service operators (operator token).
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
entry_id | path | string (uuid) | Yes | |
X-VMYard-Operator-Token | header | string | Yes | Operator token from the service configuration |
Request body (application/json, WaitlistDecisionRequest)
| Field | Type | Required | Description |
|---|---|---|---|
operator | string | Yes | The individual operator acting, 1-200 characters. |
reason | string | Yes | Why, 1-500 characters. |
Responses
| Status | Description | Body |
|---|---|---|
200 | — | WaitlistDecisionDto |
401 | Not signed in, or the API key is malformed, expired, or revoked (unauthenticated, invalid_api_key). | ProblemDetails |
404 | operator access is not configured or the entry is unknown | ProblemDetails |
409 | waitlist_decision_conflict: the entry is not approved | ProblemDetails |
422 | Invalid request (invalid_request); field_errors names the fields. | ProblemDetails |
curl -X POST "$VMYARD_API_URL/v1/operator/waitlist/$ENTRY_ID/revoke" \
-H "X-VMYard-Operator-Token: $X_VMYARD_OPERATOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"operator": "string",
"reason": "string"
}'{
"changed": false,
"entry": {
"access_grant_id": "6f1c2d3e-4b5a-4c7d-8e9f-0a1b2c3d4e5f",
"company": "string",
"created_at": "string",
"decided_at": "string",
"decided_by": "string",
"decision_reason": "string",
"email": "ada@example.com",
"id": "6f1c2d3e-4b5a-4c7d-8e9f-0a1b2c3d4e5f",
"name": "dev",
"raw_answers": {},
"status": "pending",
"updated_at": "string",
"use_case": "string"
},
"grant": {
"created_at": "string",
"credited_at": "string",
"credited_organization_id": "6f1c2d3e-4b5a-4c7d-8e9f-0a1b2c3d4e5f",
"email": "ada@example.com",
"granted_by": "string",
"id": "6f1c2d3e-4b5a-4c7d-8e9f-0a1b2c3d4e5f",
"initial_credit_micros": 0,
"provider": "github",
"reason": "string",
"revoke_reason": "string",
"revoked_at": "string",
"revoked_by": "string",
"subject": "string"
},
"notification": "sent"
}List access grants (operators)
GET /v1/operator/access-grants
Access grants, newest first.
- Authentication: none on this route.
- Who: Service operators (operator token).
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
include_revoked | query | boolean | No | Include revoked grants (default false). |
limit | query | integer | No | 1-500, default 100; newest first. |
X-VMYard-Operator-Token | header | string | Yes | Operator token from the service configuration |
Responses
| Status | Description | Body |
|---|---|---|
200 | — | AccessGrantPage |
401 | Not signed in, or the API key is malformed, expired, or revoked (unauthenticated, invalid_api_key). | ProblemDetails |
404 | operator access is not configured | ProblemDetails |
curl "$VMYARD_API_URL/v1/operator/access-grants" \
-H "X-VMYard-Operator-Token: $X_VMYARD_OPERATOR_TOKEN"{
"items": [
{
"created_at": "string",
"credited_at": "string",
"credited_organization_id": "6f1c2d3e-4b5a-4c7d-8e9f-0a1b2c3d4e5f",
"email": "ada@example.com",
"granted_by": "string",
"id": "6f1c2d3e-4b5a-4c7d-8e9f-0a1b2c3d4e5f",
"initial_credit_micros": 0,
"provider": "github",
"reason": "string",
"revoke_reason": "string",
"revoked_at": "string",
"revoked_by": "string",
"subject": "string"
}
]
}Grant access (operators)
POST /v1/operator/access-grants
Grant access without a waitlist entry: a verified login email, or one
sign-in identity (provider and subject, such as an ERP.AI account's
OIDC subject). No email is sent.
- Authentication: none on this route.
- Who: Service operators (operator token).
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-VMYard-Operator-Token | header | string | Yes | Operator token from the service configuration |
Request body (application/json, CreateAccessGrantRequest)
| Field | Type | Required | Description |
|---|---|---|---|
operator | string | Yes | The individual operator acting, 1-200 characters. |
email | string | null | No | Grant a verified login email; or name provider and subject. |
initial_credit_micros | integer | null | No | As on approval; defaults to the service's initial credit, 0 for none. |
provider | string | null | No | A configured sign-in provider such as erpai. |
reason | string | null | No | |
subject | string | null | No | The provider's subject (sub) for the account, 1-255 characters. |
Responses
| Status | Description | Body |
|---|---|---|
200 | An active grant already named this person | AccessGrantCreatedDto |
201 | — | AccessGrantCreatedDto |
401 | Not signed in, or the API key is malformed, expired, or revoked (unauthenticated, invalid_api_key). | ProblemDetails |
404 | operator access is not configured | ProblemDetails |
422 | Invalid request (invalid_request); field_errors names the fields. | ProblemDetails |
curl -X POST "$VMYARD_API_URL/v1/operator/access-grants" \
-H "X-VMYard-Operator-Token: $X_VMYARD_OPERATOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"operator": "string"
}'{
"created": false,
"grant": {
"created_at": "string",
"credited_at": "string",
"credited_organization_id": "6f1c2d3e-4b5a-4c7d-8e9f-0a1b2c3d4e5f",
"email": "ada@example.com",
"granted_by": "string",
"id": "6f1c2d3e-4b5a-4c7d-8e9f-0a1b2c3d4e5f",
"initial_credit_micros": 0,
"provider": "github",
"reason": "string",
"revoke_reason": "string",
"revoked_at": "string",
"revoked_by": "string",
"subject": "string"
}
}Revoke an access grant (operators)
POST /v1/operator/access-grants/{grant_id}/revoke
Revoke a grant; a waitlist entry approved through it becomes revoked. Revoking a revoked grant changes nothing.
- Authentication: none on this route.
- Who: Service operators (operator token).
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
grant_id | path | string (uuid) | Yes | |
X-VMYard-Operator-Token | header | string | Yes | Operator token from the service configuration |
Request body (application/json, WaitlistDecisionRequest)
| Field | Type | Required | Description |
|---|---|---|---|
operator | string | Yes | The individual operator acting, 1-200 characters. |
reason | string | Yes | Why, 1-500 characters. |
Responses
| Status | Description | Body |
|---|---|---|
200 | — | AccessGrantDto |
401 | Not signed in, or the API key is malformed, expired, or revoked (unauthenticated, invalid_api_key). | ProblemDetails |
404 | operator access is not configured or the grant is unknown | ProblemDetails |
422 | Invalid request (invalid_request); field_errors names the fields. | ProblemDetails |
curl -X POST "$VMYARD_API_URL/v1/operator/access-grants/$GRANT_ID/revoke" \
-H "X-VMYard-Operator-Token: $X_VMYARD_OPERATOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"operator": "string",
"reason": "string"
}'{
"created_at": "string",
"credited_at": "string",
"credited_organization_id": "6f1c2d3e-4b5a-4c7d-8e9f-0a1b2c3d4e5f",
"email": "ada@example.com",
"granted_by": "string",
"id": "6f1c2d3e-4b5a-4c7d-8e9f-0a1b2c3d4e5f",
"initial_credit_micros": 0,
"provider": "github",
"reason": "string",
"revoke_reason": "string",
"revoked_at": "string",
"revoked_by": "string",
"subject": "string"
}