---
title: "Mint a sandbox member invite magic link."
method: POST
path: "/v1/orgs/{orgId}/sandbox-invites"
tags: ["members"]
---

# Mint a sandbox member invite magic link.

`POST /v1/orgs/{orgId}/sandbox-invites`

## Request

- Base URL: `http://localhost:8080`
- URL: `http://localhost:8080/v1/orgs/{orgId}/sandbox-invites`
- Auth: one of:
  - API key in cookie `dvt_session`
  - HTTP bearer

Creates a fresh throwaway editor user and a single-use sandbox login token,
returning a magic link that drops the invitee into the sandbox org via the
existing `/auth/sandbox` exchange. Available only for sandbox orgs (`is_sandbox`).
Admin or owner only (editors lack `MemberManage` and are denied by the gate).

The supplied `email` is used only as the invitee's `display_name` — it is never
written to `users.email` (which carries a randomised `@dvt.internal` handle).
This is the non-WorkOS invite path for sandbox orgs (ADR-0042 D2 Amendment, DVT-596).

Caps: at most 3 total members per sandbox org (409); at most 10 invite tokens per
org per hour (429).

## Request body

- object
  - `email` string, email, required: The invitee's email. Used as display_name only — not the identity key. Must be a valid email shape (max 254 chars, single @, domain with a dot).

## Response `201`

Invite minted. The inviteUrl is a single-use magic link for the sandbox.

- object
  - `data` object
    - `inviteUrl` string, uri: Single-use magic link to the /sandbox-login?token=… page, which exchanges the token via /auth/sandbox.
    - `expiresAt` string, date-time: When the invite token (and sandbox org) expires (RFC 3339).
    - `invitedDisplayName` string: The email supplied as display_name for the invited user.
  - `meta` Meta: Response metadata.
    - `requestId` string, required: Correlates with the X-Request-Id header.
    - `total` integer: Item count, present on collection responses.
    - `nextCursor` string, nullable: Opaque keyset-pagination cursor, present on paginated responses (e.g. GET /v1/dashboards) when more rows exist beyond this page. Pass it back as the `cursor` query param to fetch the next page; absent or null on the last page.
    - `roleResolveDegraded` boolean: Snowflake mode only (DVT-2260), on GET /v1/dashboards: present and true when the caller's live Snowflake role resolution failed or was unavailable — role-shared dashboards may be missing from this page. Omitted (not merely false) whenever resolution succeeded or the role-share arm does not apply (off snowflake mode, an org admin/owner, or off the ingress listener).

## Other responses

- `400`: Malformed request.
- `401`: Missing, invalid, or expired session.
- `403`: The caller's role does not permit this action.
- `404`: Resource does not exist.
- `409`: The sandbox member cap (3) has been reached.
- `429`: Per-org invite rate limit exceeded (10 per hour).

---

[API](https://skmtc.dev/dvt/apis/dvt-rest-api.md) · [All operations](https://skmtc.dev/dvt/apis/dvt-rest-api/llms.txt) · [OpenAPI document](https://skmtc.dev/dvt/apis/dvt-rest-api/revisions/00016f504165?raw)
