curl --request POST \
--url https://api.gigstack.io/v2/users/me/account-approvals \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"operation_id": "00000000-0000-4000-8000-000000000001",
"action": "api_keys.generate",
"team_id": "team_example",
"payload": {}
}
'{
"success": true,
"data": {
"id": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"operation_id": "00000000-0000-4000-8000-000000000001",
"action": "api_keys.generate",
"team": {
"id": "team_example",
"legal_name": null,
"tax_id": null
},
"billing_account_id": "billing_example",
"payload": {},
"requested_modes": [
true,
false
],
"effect_scope": "team_credentials",
"status": "pending",
"created_at": 1700000000000,
"expires_at": 1700000600000,
"completed_at": null,
"review_url": "https://app.gigstack.pro/account/approvals/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"can_cancel": true,
"disclosure_version": "credential-approval-v1",
"existing_key_ids": [],
"terms": null,
"receipt": null,
"error": null,
"membership_change": null,
"invitation_change": null,
"managed_identity_change": null,
"managed_identity_execution": null,
"managed_session_change": null,
"managed_session_execution": null
},
"timestamp": 1700000000000
}{
"success": false,
"error": {
"code": "invalid_request_body",
"message": "An error occurred"
},
"timestamp": 1767225600000
}Prepare an account approval
Requires a verified personal Firebase or MCP identity and current action authority. Team API/OAuth keys cannot prepare approvals. Reads and cancellation bind the creator and originating MCP credential/mode. Browser confirmation rechecks current authority, credential validity and relevant account state. Preparation never issues a credential or accepts terms.
Persist a UUIDv4 operation_id before the first call. After a timeout, repeat only the exact action, scope and normalized payload with the same ID; it retrieves the existing intent. Changed input returns 409 operation_conflict. API actions require an empty payload; MCP creation requires a trimmed name and explicit livemode. Open review_url in the authenticated browser to review and confirm. The selected MCP team is initial context, not a user-access security ceiling. Select an authorized current team with the team query parameter for authentication context; preparation should use the same team as body.team_id. This does not alter the originating credential or mode.
Membership actions require the current team owner. Prepare a transfer with payload , or an admin promotion/addition with payload . The browser reviews the frozen target identity, current role and account-wide consequences. Team membership is shared across production and test: requested_modes is empty for these actions, not a sandbox-only promise. The old owner remains an administrator after transfer; billing-account ownership is unchanged. Membership execution returns no credentials. Ordinary editor/viewer changes and permissions-only patches retain their existing direct routes and authority.
Administrator invitations require team.invitations.create_admin with team_id, or billing_account.invitations.create_admin with billing_account_id and no team_id. Payload must contain email and an explicit send_email boolean. Only the current canonical scope owner can approve; billing administrators or team owners do not substitute for the billing-account owner. Account-wide membership applies across live and test. To recover an existing unexpired pending admin invitation, supply existing_invitation_id and send_email:false. Review freezes the recipient address, scope, role, expiry and delivery choice. Completed means recorded, not emailed or joined. Read the receipt invitation through /users/me/account-invitations/ for delivery status. Missing canonical owner returns 409 canonical_owner_required and requires support recovery. Managed administrator creation uses managed_users.create_admin with team_id and an email/profile payload. Both canonical team and billing owners must be the initiating person. The first browser execution creates a disabled identity and its bootstrap records; a second fresh browser review is required to grant membership and activate it. No credentials or email are delivered. Unknown outcomes require reconcile, never another creation or activation attempt. Where owners differ, create a nonadmin managed user then use owner-reviewed promotion.
Managed session actions use managed_users.issue_session or managed_users.revoke_sessions with team_id and exactly . The current canonical owner of the billing account and every reachable team must be the initiating person. Private provenance and current Auth incarnation are required; historical API labels alone are insufficient. The frozen managed_session_change includes inherited grants and exact prior issuance/revocation attempts. Access spans live and test (requested_modes:[]), with no lifetime tenant ceiling. Only a separately reviewed browser action can issue access or revoke refresh tokens. Unknown attempts are never automatically replayed. A custom_token_expires_at deadline limits exchange, not a redeemed Firebase session. Revocation does not invalidate an outstanding custom token or necessarily already-issued ID tokens; prior unknown issuance remains unknown. Session preparation is disabled by default and always unavailable in production until an authoritative reverse-index strategy exists. Only explicit staging prototype configuration enables bounded projected scans. Unavailable or incomplete scope returns 503 without issuance. This contract does not establish deployment availability.
curl --request POST \
--url https://api.gigstack.io/v2/users/me/account-approvals \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"operation_id": "00000000-0000-4000-8000-000000000001",
"action": "api_keys.generate",
"team_id": "team_example",
"payload": {}
}
'{
"success": true,
"data": {
"id": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"operation_id": "00000000-0000-4000-8000-000000000001",
"action": "api_keys.generate",
"team": {
"id": "team_example",
"legal_name": null,
"tax_id": null
},
"billing_account_id": "billing_example",
"payload": {},
"requested_modes": [
true,
false
],
"effect_scope": "team_credentials",
"status": "pending",
"created_at": 1700000000000,
"expires_at": 1700000600000,
"completed_at": null,
"review_url": "https://app.gigstack.pro/account/approvals/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"can_cancel": true,
"disclosure_version": "credential-approval-v1",
"existing_key_ids": [],
"terms": null,
"receipt": null,
"error": null,
"membership_change": null,
"invitation_change": null,
"managed_identity_change": null,
"managed_identity_execution": null,
"managed_session_change": null,
"managed_session_execution": null
},
"timestamp": 1700000000000
}{
"success": false,
"error": {
"code": "invalid_request_body",
"message": "An error occurred"
},
"timestamp": 1767225600000
}Authorizations
Authentication Method: HTTP Bearer token.
The runtime requires the literal Bearer prefix — a bare token in the
Authorization header is rejected with 401 unauthorized.
Header Format: Authorization: Bearer YOUR_API_KEY
Your API key is a JWT. Live keys operate on live data (livemode: true);
test keys operate on isolated test data (livemode: false).
Get your key at: app.gigstack.pro/settings?tab=api
Errors: credential failures are answered by the authentication layer with a raw
{ "message": … } body, not the standardized envelope — 401 for a missing, malformed or
expired token, 403 for a revoked key or a plan without API access. See the Unauthorized
and AuthForbidden responses.
Query Parameters
gigstack Connect: Target team ID for multi-team access.
Requires gigstack Connect enabled on your team and shared billing account.
Also requires the multipleIssuerAccounts feature on your plan. Requests targeting a
team other than the one your API key belongs to return 403 without it.
Only API keys can use it: an OAuth access token sent with another team's id is rejected with
403 Team mismatch with OAuth token.
Optional — omit it entirely unless you are acting on another team. It deliberately
carries no example value so generated snippets do not emit ?team=undefined; when the
parameter is absent, the team is derived from your API key.
Example: ?team=team_xyz789
Body
- Option 1
- Option 2
- Option 3
- Option 4
- Option 5
- Option 6
- Option 7
- Option 8
^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$api_keys.generate, api_keys.rotate ^[A-Za-z0-9_-]{1,128}$Show child attributes
Show child attributes
^[A-Za-z0-9_-]{1,128}$