Contract
- shape
- entity
- authority
- act
- evidence
- none
- subscription
- false
- permission
- any one of: org.admin (carried by the caller's role template in the org `org_id`); account.owner (account role owner or higher in the account of the org `org_id`); a deactivated caller is refused first
- idempotency
- keyed
- emits
- service_account.created
- MCP tool
- create_service_account
- decision_set
- approve, reject
- REST
- POST https://api.containertradehq.com/v1/cap/create_service_account
Through MCP this call returns an approval request first; see Approvals.
Idempotency: keyed by the caller's Idempotency-Key, which is required: the same key and inputs replay the first result, the same key with other inputs is 409 idempotency_key_reused
Inputs
| name | type | required | validation |
|---|---|---|---|
| org_id | org_id | required | tradehq-org-id; 1 to 20 characters The live org the account belongs to. |
| name | text | required | 1 to 80 characters What the account is for, such as the integration that holds its keys. |
| owner_user_id | user_id | required | tradehq-user-id; 1 to 20 characters The primary owner: an active member of the org. |
| backup_owner_user_id | user_id | required | tradehq-user-id; 1 to 20 characters The backup owner: another active member of the org, who takes over when the primary is deactivated. |
| role_template_id | text | required | 1 to 64 characters The role template the account acts under: a shipped one or the org's own, never owner or admin. |
| expires_in_days | integer | optional | 1 to 365; default 365 Days until the account and every key of it stop working, at most 365 (the default). update_service_account renews it. |
| mode | one_of | optional | one of live, test live (the default) or test. Its keys are sk_live_ or sk_test_ to match; it never changes. |
Response
service_account_id· string · The account's id.org_id· string · The live org it belongs to.name· string · What it is for.owner_user_id· stringnull · Its primary owner; null only while it is suspended for want of one.backup_owner_user_id· stringnull · Its backup owner, who takes over when the primary is deactivated; null once that has happened.role_template_id· string · The role template it acts under: never Owner or Admin.mode· string · live or test; its keys are sk_live_ or sk_test_ to match.status· string · active; suspended when its last owner was deactivated, until an admin reassigns it; disabled, which is final; or expired.expires_at· string · When it and every key of it stop working, unless renewed.keys· integer · How many working keys it holds.last_used_at· stringnull · The start of the last minute any key of it was served a request; null if never.created_at· string · When it was made.created_by· string · Who made it.
Full JSON Schema
{
"type": "object",
"properties": {
"service_account_id": {
"type": "string",
"description": "The account's id.",
"x-data-class": "operational"
},
"org_id": {
"type": "string",
"minLength": 1,
"maxLength": 20,
"pattern": "^[A-Za-z0-9_-]{1,20}$",
"format": "tradehq-org-id",
"description": "The live org it belongs to.",
"x-data-class": "operational"
},
"name": {
"type": "string",
"description": "What it is for.",
"x-data-class": "operational"
},
"owner_user_id": {
"type": [
"string",
"null"
],
"minLength": 1,
"maxLength": 20,
"pattern": "^[A-Za-z0-9_-]{1,20}$",
"format": "tradehq-user-id",
"description": "Its primary owner; null only while it is suspended for want of one.",
"x-data-class": "operational"
},
"backup_owner_user_id": {
"type": [
"string",
"null"
],
"minLength": 1,
"maxLength": 20,
"pattern": "^[A-Za-z0-9_-]{1,20}$",
"format": "tradehq-user-id",
"description": "Its backup owner, who takes over when the primary is deactivated; null once that has happened.",
"x-data-class": "operational"
},
"role_template_id": {
"type": "string",
"description": "The role template it acts under: never Owner or Admin.",
"x-data-class": "operational"
},
"mode": {
"type": "string",
"enum": [
"live",
"test"
],
"description": "live or test; its keys are sk_live_ or sk_test_ to match.",
"x-data-class": "operational"
},
"status": {
"type": "string",
"enum": [
"active",
"suspended",
"disabled",
"expired"
],
"description": "active; suspended when its last owner was deactivated, until an admin reassigns it; disabled, which is final; or expired.",
"x-data-class": "operational"
},
"expires_at": {
"type": "string",
"format": "date-time",
"description": "When it and every key of it stop working, unless renewed.",
"x-data-class": "operational"
},
"keys": {
"type": "integer",
"description": "How many working keys it holds.",
"x-data-class": "operational"
},
"last_used_at": {
"type": [
"string",
"null"
],
"format": "date-time",
"description": "The start of the last minute any key of it was served a request; null if never.",
"x-data-class": "operational"
},
"created_at": {
"type": "string",
"format": "date-time",
"description": "When it was made.",
"x-data-class": "operational"
},
"created_by": {
"type": "string",
"minLength": 1,
"maxLength": 20,
"pattern": "^[A-Za-z0-9_-]{1,20}$",
"format": "tradehq-user-id",
"description": "Who made it.",
"x-data-class": "operational"
}
},
"required": [
"service_account_id",
"org_id",
"name",
"owner_user_id",
"backup_owner_user_id",
"role_template_id",
"mode",
"status",
"expires_at",
"keys",
"last_used_at",
"created_at",
"created_by"
],
"additionalProperties": false
} Refusals
org_is_a_test_twin· 422 · the org is a test twin; make the account on its live org with mode testowners_must_differ· 422 · the primary and the backup owner are the same personowner_not_active_member· 422 · an owner is deactivated or not a member of the orgrole_template_not_assignable· 422 · the role template is Owner, Admin, a guest's, or carries org.admin or role.manageunknown_role_template· 422 · the role template is neither shipped nor the org's ownpermission_not_held· 422 · the role template carries a permission the calling admin's own role does notidempotency_key_reused· 409 · this Idempotency-Key already made a service account with different inputsretry_key_mismatch· 409 · the Idempotency-Key was already used with different inputsretry_key_in_flight· 409 · a request with this Idempotency-Key is still runningretry_key_lost· 409 · another request took over this Idempotency-Key first; no account was made
The platform refusals apply to every call: version, authentication, authority, validation and rate limits, each in the same envelope.
Surfaces
- Mobile: degraded: composition
- MCP: approval required
- Voice: degraded: composition
- OneBox: no document originates a service account
- Outbound: crosses to no counterparty
Events
service_account.createdaudit_only
Related
create_api_key, get_api_usage, get_view_default, list_saved_views, save_view, set_my_view_default, set_org_view_default, update_service_account