> For the complete documentation index, see [llms.txt](https://developer.celigo.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developer.celigo.com/api/api-reference/end-users.md).

# End Users

End users are people who consume an account's MCP servers without getting workspace access — they sign in through MCP OAuth, optionally via an external IdP. Use these endpoints to invite end users (singly or in bulk), list and revoke them, and inspect the effective MCP tool access compiled from their grants, groups, and roles. An end user's access record is an ashare, so editing its grants and suspending it use the `/v1/ashares` routes shared with workspace users. The account owner is never an end user: owners already have MCP access without an end-user record, the invite refuses the owner's address (`owner_self_invite_not_allowed`), and the owner never appears in these lists.

### End user schema

## The EndUser object

```json
{"openapi":"3.2.0","info":{"title":"End Users","version":"1.0.0"},"components":{"schemas":{"EndUser":{"type":"object","description":"An end user's access record in the account. End users authenticate through\nMCP OAuth (optionally via an external IdP) to use MCP servers; they do not\nget workspace access. The `_id` is the access-record id, not the user's own\nid — the user's identity is in `_sharedWithUserId`.","required":["_id"],"properties":{"_id":{"type":"string","format":"objectId","readOnly":true,"description":"Access-record id for this end user in the account."},"_userId":{"type":"string","format":"objectId","readOnly":true,"description":"Account owner's user id."},"_sharedWithUserId":{"type":"string","format":"objectId","readOnly":true,"description":"The end user's own user id."},"userType":{"type":"string","enum":["end-user"],"description":"Distinguishes end-user access records from workspace access records."},"provisionedBy":{"type":"string","enum":["invite","jit"],"description":"How this end-user record was created."},"accepted":{"type":"boolean","description":"When true, the end user has completed invite setup (or was JIT-provisioned)."},"dismissed":{"type":"boolean","description":"When true, the end user has declined the invitation."},"disabled":{"type":"boolean","description":"When true, the end user's access is suspended without deleting the\nrecord. Changed only by `PUT /v1/ashares/{_ashareId}/disable` — a\nvalue sent on the update operation is not applied."},"groupMemberships":{"type":"array","description":"Groups this end user belongs to, with the source of each membership.","items":{"$ref":"#/components/schemas/GroupMembership"}},"resourceGrants":{"type":"array","description":"Direct resource grants on this end user, in addition to any group- or role-derived access.","items":{"$ref":"#/components/schemas/ResourceGrant"}},"_roleIds":{"type":"array","description":"Roles assigned directly to this end user.","items":{"type":"string","format":"objectId"}},"email":{"type":"string","format":"email","readOnly":true,"description":"Email address of the end user, joined from the user record."},"name":{"type":"string","readOnly":true,"description":"Display name of the end user, joined from the user record."},"lastSignIn":{"type":["string","null"],"format":"date-time","readOnly":true,"description":"When the end user last signed in. Null when they have never signed in."},"hasWorkspaceShare":{"type":"boolean","readOnly":true,"description":"When true, the same person also has an active workspace access record on this account."},"createdAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the end-user record was created."},"lastModified":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the end-user record was last updated."}}},"GroupMembership":{"type":"object","description":"An end user's membership in a group, with the source that created it.","properties":{"_groupId":{"type":"string","format":"objectId","description":"Group the end user belongs to."},"source":{"type":"string","enum":["manual","idp"],"description":"How the membership was created. IdP-synced memberships cannot be\nremoved through the group members API — change the IdP group mapping\ninstead."}}},"ResourceGrant":{"type":"object","description":"Grants access to a resource (currently MCP servers only). A grant names\nthe resource, or applies as a wildcard across all resources of the type,\nand lists the capabilities granted on it.","required":["resourceType","capabilities"],"properties":{"resourceType":{"type":"string","enum":["mcpServer"],"description":"Resource type this grant applies to."},"_resourceId":{"type":["string","null"],"format":"objectId","description":"MCP server this grant applies to. Omit or set to null for a wildcard\ngrant across all MCP servers in the account."},"capabilities":{"type":"array","minItems":1,"description":"Capabilities granted on the target resource.","items":{"type":"string","description":"Capability string. For `mcpServer` grants: `tool:all`,\n`tool:<24-char-hex-id>` (an IO tool `_toolId` or attached prompt `_id`),\n`api:all`, `api:<24-char-hex-apiId>`, or\n`pset:<24-char-hex-permissionSetId>` referencing a permission set\ndefined on the target MCP server."}}}}}}}
```

## List end users

> Returns the account's end users with identity fields (\`email\`, \`name\`,\
> \`lastSignIn\`) joined from each user record, plus a computed\
> \`hasWorkspaceShare\` flag indicating whether the same person also holds a\
> workspace access record. The account owner is never listed: owners\
> have MCP access without an end-user record, so none exists for them.\
> Requires account owner or administrator access.

```json
{"openapi":"3.2.0","info":{"title":"End Users","version":"1.0.0"},"tags":[{"name":"End Users","description":"End users are people who consume an account's MCP servers without\ngetting workspace access — they sign in through MCP OAuth, optionally\nvia an external IdP. Use these endpoints to invite end users (singly or\nin bulk), list and revoke them, and inspect the effective MCP tool\naccess compiled from their grants, groups, and roles. An end user's\naccess record is an ashare, so editing its grants and suspending it\nuse the `/v1/ashares` routes shared with workspace users. The account\nowner is never an end user: owners already have MCP access without an\nend-user record, the invite refuses the owner's address\n(`owner_self_invite_not_allowed`), and the owner never appears in\nthese lists.\n\n## End user schema\n\n{% openapi-schemas spec=\"enduser\" schemas=\"EndUser\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"EndUser":{"type":"object","description":"An end user's access record in the account. End users authenticate through\nMCP OAuth (optionally via an external IdP) to use MCP servers; they do not\nget workspace access. The `_id` is the access-record id, not the user's own\nid — the user's identity is in `_sharedWithUserId`.","required":["_id"],"properties":{"_id":{"type":"string","format":"objectId","readOnly":true,"description":"Access-record id for this end user in the account."},"_userId":{"type":"string","format":"objectId","readOnly":true,"description":"Account owner's user id."},"_sharedWithUserId":{"type":"string","format":"objectId","readOnly":true,"description":"The end user's own user id."},"userType":{"type":"string","enum":["end-user"],"description":"Distinguishes end-user access records from workspace access records."},"provisionedBy":{"type":"string","enum":["invite","jit"],"description":"How this end-user record was created."},"accepted":{"type":"boolean","description":"When true, the end user has completed invite setup (or was JIT-provisioned)."},"dismissed":{"type":"boolean","description":"When true, the end user has declined the invitation."},"disabled":{"type":"boolean","description":"When true, the end user's access is suspended without deleting the\nrecord. Changed only by `PUT /v1/ashares/{_ashareId}/disable` — a\nvalue sent on the update operation is not applied."},"groupMemberships":{"type":"array","description":"Groups this end user belongs to, with the source of each membership.","items":{"$ref":"#/components/schemas/GroupMembership"}},"resourceGrants":{"type":"array","description":"Direct resource grants on this end user, in addition to any group- or role-derived access.","items":{"$ref":"#/components/schemas/ResourceGrant"}},"_roleIds":{"type":"array","description":"Roles assigned directly to this end user.","items":{"type":"string","format":"objectId"}},"email":{"type":"string","format":"email","readOnly":true,"description":"Email address of the end user, joined from the user record."},"name":{"type":"string","readOnly":true,"description":"Display name of the end user, joined from the user record."},"lastSignIn":{"type":["string","null"],"format":"date-time","readOnly":true,"description":"When the end user last signed in. Null when they have never signed in."},"hasWorkspaceShare":{"type":"boolean","readOnly":true,"description":"When true, the same person also has an active workspace access record on this account."},"createdAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the end-user record was created."},"lastModified":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the end-user record was last updated."}}},"GroupMembership":{"type":"object","description":"An end user's membership in a group, with the source that created it.","properties":{"_groupId":{"type":"string","format":"objectId","description":"Group the end user belongs to."},"source":{"type":"string","enum":["manual","idp"],"description":"How the membership was created. IdP-synced memberships cannot be\nremoved through the group members API — change the IdP group mapping\ninstead."}}},"ResourceGrant":{"type":"object","description":"Grants access to a resource (currently MCP servers only). A grant names\nthe resource, or applies as a wildcard across all resources of the type,\nand lists the capabilities granted on it.","required":["resourceType","capabilities"],"properties":{"resourceType":{"type":"string","enum":["mcpServer"],"description":"Resource type this grant applies to."},"_resourceId":{"type":["string","null"],"format":"objectId","description":"MCP server this grant applies to. Omit or set to null for a wildcard\ngrant across all MCP servers in the account."},"capabilities":{"type":"array","minItems":1,"description":"Capabilities granted on the target resource.","items":{"type":"string","description":"Capability string. For `mcpServer` grants: `tool:all`,\n`tool:<24-char-hex-id>` (an IO tool `_toolId` or attached prompt `_id`),\n`api:all`, `api:<24-char-hex-apiId>`, or\n`pset:<24-char-hex-permissionSetId>` referencing a permission set\ndefined on the target MCP server."}}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"403-forbidden":{"description":"Forbidden. The authenticated caller does not have permission to perform this operation.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/endusers":{"get":{"summary":"List end users","operationId":"listEndUsers","tags":["End Users"],"description":"Returns the account's end users with identity fields (`email`, `name`,\n`lastSignIn`) joined from each user record, plus a computed\n`hasWorkspaceShare` flag indicating whether the same person also holds a\nworkspace access record. The account owner is never listed: owners\nhave MCP access without an end-user record, so none exists for them.\nRequires account owner or administrator access.","parameters":[{"name":"provisionedBy","in":"query","required":false,"description":"Return only end users created by the given provisioning source.","schema":{"type":"string","enum":["invite","jit"]}}],"responses":{"200":{"description":"List of end users.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EndUser"}}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"403":{"$ref":"#/components/responses/403-forbidden"}}}}}}
```

## Invite an end user

> Finds or creates the user by email, creates an end-user access record,\
> applies the requested group memberships and direct grants, and sends an\
> invite email. The account owner cannot be invited as an end user\
> (\`owner\_self\_invite\_not\_allowed\`): owners already have MCP access\
> without an end-user record, so there is nothing to grant — test\
> end-user access with a different address. Requires account owner or\
> administrator access.

```json
{"openapi":"3.2.0","info":{"title":"End Users","version":"1.0.0"},"tags":[{"name":"End Users","description":"End users are people who consume an account's MCP servers without\ngetting workspace access — they sign in through MCP OAuth, optionally\nvia an external IdP. Use these endpoints to invite end users (singly or\nin bulk), list and revoke them, and inspect the effective MCP tool\naccess compiled from their grants, groups, and roles. An end user's\naccess record is an ashare, so editing its grants and suspending it\nuse the `/v1/ashares` routes shared with workspace users. The account\nowner is never an end user: owners already have MCP access without an\nend-user record, the invite refuses the owner's address\n(`owner_self_invite_not_allowed`), and the owner never appears in\nthese lists.\n\n## End user schema\n\n{% openapi-schemas spec=\"enduser\" schemas=\"EndUser\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"InviteRequest":{"type":"object","description":"Invitation details for a single end user.","required":["email"],"properties":{"email":{"type":"string","format":"email","description":"Email address to invite. Normalized to lowercase and trimmed."},"name":{"type":"string","description":"Display name for the invited user. Defaults to the email local-part when omitted."},"groupIds":{"type":"array","description":"Groups to add the end user to as manual memberships.","items":{"type":"string","format":"objectId"}},"directGrants":{"type":"array","description":"Direct resource grants placed on the new end-user record.","items":{"$ref":"#/components/schemas/ResourceGrant"}},"resourceGrants":{"type":"array","description":"Alias for `directGrants`; send one or the other.","items":{"$ref":"#/components/schemas/ResourceGrant"}}}},"ResourceGrant":{"type":"object","description":"Grants access to a resource (currently MCP servers only). A grant names\nthe resource, or applies as a wildcard across all resources of the type,\nand lists the capabilities granted on it.","required":["resourceType","capabilities"],"properties":{"resourceType":{"type":"string","enum":["mcpServer"],"description":"Resource type this grant applies to."},"_resourceId":{"type":["string","null"],"format":"objectId","description":"MCP server this grant applies to. Omit or set to null for a wildcard\ngrant across all MCP servers in the account."},"capabilities":{"type":"array","minItems":1,"description":"Capabilities granted on the target resource.","items":{"type":"string","description":"Capability string. For `mcpServer` grants: `tool:all`,\n`tool:<24-char-hex-id>` (an IO tool `_toolId` or attached prompt `_id`),\n`api:all`, `api:<24-char-hex-apiId>`, or\n`pset:<24-char-hex-permissionSetId>` referencing a permission set\ndefined on the target MCP server."}}}},"InviteResponse":{"type":"object","description":"Result of a successful single invite.","properties":{"_userId":{"type":"string","format":"objectId","description":"Account owner's user id."},"_ashareId":{"type":"string","format":"objectId","description":"Access-record id of the newly created end user."},"status":{"type":"string","enum":["invited"],"description":"Outcome of the invite."}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"403-forbidden":{"description":"Forbidden. The authenticated caller does not have permission to perform this operation.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422-unprocessable-entity":{"description":"Unprocessable entity. The request was well-formed but was unable to be followed due to semantic errors.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/endusers/invite":{"post":{"summary":"Invite an end user","operationId":"inviteEndUser","tags":["End Users"],"description":"Finds or creates the user by email, creates an end-user access record,\napplies the requested group memberships and direct grants, and sends an\ninvite email. The account owner cannot be invited as an end user\n(`owner_self_invite_not_allowed`): owners already have MCP access\nwithout an end-user record, so there is nothing to grant — test\nend-user access with a different address. Requires account owner or\nadministrator access.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteRequest"}}}},"responses":{"201":{"description":"End user invited.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteResponse"}}}},"400":{"description":"The email is missing or invalid (`email_invalid`), or it is the\naccount owner's address (`owner_self_invite_not_allowed` — the owner\nalready has MCP access without an end-user record).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"403":{"$ref":"#/components/responses/403-forbidden"},"409":{"description":"An end-user record already exists for this user in the account.\nError code: `enduser_ashare_exists`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/422-unprocessable-entity"}}}}}}
```

## Invite end users in bulk

> Invites 1–100 end users in one request, applying the same optional\
> \`groupIds\` and \`directGrants\` to every invite. Processing is sequential\
> and partial-success: a failed item never aborts the batch, so the\
> response is HTTP 200 with a per-email result even when some items fail.\
> Only top-level structural errors (missing or non-array \`emails\`, more\
> than 100 emails, non-array \`groupIds\`/\`directGrants\`) return 400.\
> Requires account owner or administrator access.

```json
{"openapi":"3.2.0","info":{"title":"End Users","version":"1.0.0"},"tags":[{"name":"End Users","description":"End users are people who consume an account's MCP servers without\ngetting workspace access — they sign in through MCP OAuth, optionally\nvia an external IdP. Use these endpoints to invite end users (singly or\nin bulk), list and revoke them, and inspect the effective MCP tool\naccess compiled from their grants, groups, and roles. An end user's\naccess record is an ashare, so editing its grants and suspending it\nuse the `/v1/ashares` routes shared with workspace users. The account\nowner is never an end user: owners already have MCP access without an\nend-user record, the invite refuses the owner's address\n(`owner_self_invite_not_allowed`), and the owner never appears in\nthese lists.\n\n## End user schema\n\n{% openapi-schemas spec=\"enduser\" schemas=\"EndUser\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"BulkInviteRequest":{"type":"object","description":"Batch invitation for up to 100 end users. The optional `groupIds` and\n`directGrants` are shared and applied identically to every invite in\nthe batch.","required":["emails"],"properties":{"emails":{"type":"array","minItems":1,"maxItems":100,"description":"Email addresses to invite. Normalized to lowercase, trimmed, and de-duplicated within the batch.","items":{"type":"string","format":"email"}},"groupIds":{"type":"array","description":"Groups added as manual memberships on every created end-user record.","items":{"type":"string","format":"objectId"}},"directGrants":{"type":"array","description":"Direct resource grants applied identically to every invite.","items":{"$ref":"#/components/schemas/ResourceGrant"}},"resourceGrants":{"type":"array","description":"Alias for `directGrants`; send one or the other.","items":{"$ref":"#/components/schemas/ResourceGrant"}}}},"ResourceGrant":{"type":"object","description":"Grants access to a resource (currently MCP servers only). A grant names\nthe resource, or applies as a wildcard across all resources of the type,\nand lists the capabilities granted on it.","required":["resourceType","capabilities"],"properties":{"resourceType":{"type":"string","enum":["mcpServer"],"description":"Resource type this grant applies to."},"_resourceId":{"type":["string","null"],"format":"objectId","description":"MCP server this grant applies to. Omit or set to null for a wildcard\ngrant across all MCP servers in the account."},"capabilities":{"type":"array","minItems":1,"description":"Capabilities granted on the target resource.","items":{"type":"string","description":"Capability string. For `mcpServer` grants: `tool:all`,\n`tool:<24-char-hex-id>` (an IO tool `_toolId` or attached prompt `_id`),\n`api:all`, `api:<24-char-hex-apiId>`, or\n`pset:<24-char-hex-permissionSetId>` referencing a permission set\ndefined on the target MCP server."}}}},"BulkInviteResponse":{"type":"object","description":"Batch outcome with one result per input email, in input order. Processing\nis partial-success — a failed item never aborts the batch.","required":["summary","results"],"properties":{"summary":{"type":"object","description":"Aggregate counts for the batch.","required":["total","invited","failed","skipped"],"properties":{"total":{"type":"integer","description":"Number of input emails. Equals invited + failed + skipped."},"invited":{"type":"integer","description":"Number of end users successfully invited."},"failed":{"type":"integer","description":"Number of per-email failures. Excludes items skipped as in-batch duplicates."},"skipped":{"type":"integer","description":"Number of emails skipped as duplicates within the batch."}}},"results":{"type":"array","description":"One entry per input email, in input order.","items":{"type":"object","required":["email","status"],"properties":{"email":{"type":"string","description":"The normalized email this result corresponds to."},"status":{"type":"string","enum":["invited","failed","skipped_duplicate_in_batch"],"description":"Outcome for this email."},"_userId":{"type":"string","format":"objectId","description":"Account owner's user id. Present when status is `invited`."},"_ashareId":{"type":"string","format":"objectId","description":"Access-record id of the created end user. Present when status is `invited`."},"code":{"type":"string","enum":["email_invalid","enduser_ashare_exists","owner_self_invite_not_allowed","validation_failed","invite_failed"],"description":"Failure reason. Present when status is `failed`."}}}}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"403-forbidden":{"description":"Forbidden. The authenticated caller does not have permission to perform this operation.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/endusers/invite/bulk":{"post":{"summary":"Invite end users in bulk","operationId":"inviteEndUsersBulk","tags":["End Users"],"description":"Invites 1–100 end users in one request, applying the same optional\n`groupIds` and `directGrants` to every invite. Processing is sequential\nand partial-success: a failed item never aborts the batch, so the\nresponse is HTTP 200 with a per-email result even when some items fail.\nOnly top-level structural errors (missing or non-array `emails`, more\nthan 100 emails, non-array `groupIds`/`directGrants`) return 400.\nRequires account owner or administrator access.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkInviteRequest"}}}},"responses":{"200":{"description":"Batch processed, including partial success. One result per input email.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkInviteResponse"}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"403":{"$ref":"#/components/responses/403-forbidden"}}}}}}
```

## Revoke an end user

> Soft-deletes the end-user access record and clears its group\
> memberships. Any workspace access record the same person holds is\
> unaffected. Requires account owner or administrator access.

```json
{"openapi":"3.2.0","info":{"title":"End Users","version":"1.0.0"},"tags":[{"name":"End Users","description":"End users are people who consume an account's MCP servers without\ngetting workspace access — they sign in through MCP OAuth, optionally\nvia an external IdP. Use these endpoints to invite end users (singly or\nin bulk), list and revoke them, and inspect the effective MCP tool\naccess compiled from their grants, groups, and roles. An end user's\naccess record is an ashare, so editing its grants and suspending it\nuse the `/v1/ashares` routes shared with workspace users. The account\nowner is never an end user: owners already have MCP access without an\nend-user record, the invite refuses the owner's address\n(`owner_self_invite_not_allowed`), and the owner never appears in\nthese lists.\n\n## End user schema\n\n{% openapi-schemas spec=\"enduser\" schemas=\"EndUser\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"403-forbidden":{"description":"Forbidden. The authenticated caller does not have permission to perform this operation.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}}},"paths":{"/v1/endusers/{_ashareId}":{"delete":{"summary":"Revoke an end user","operationId":"revokeEndUser","tags":["End Users"],"description":"Soft-deletes the end-user access record and clears its group\nmemberships. Any workspace access record the same person holds is\nunaffected. Requires account owner or administrator access.","parameters":[{"name":"_ashareId","in":"path","required":true,"description":"End-user access-record id (from the end users list).","schema":{"type":"string","format":"objectId"}}],"responses":{"204":{"description":"End user revoked."},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"403":{"$ref":"#/components/responses/403-forbidden"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
```

## Get an end user's effective access

> Compiles the end user's effective MCP server tool access with source\
> attribution — the union of direct grants, group grants, role grants, and\
> permission sets. The result is recomputed on every request rather than\
> cached. Requires account owner or administrator access.

```json
{"openapi":"3.2.0","info":{"title":"End Users","version":"1.0.0"},"tags":[{"name":"End Users","description":"End users are people who consume an account's MCP servers without\ngetting workspace access — they sign in through MCP OAuth, optionally\nvia an external IdP. Use these endpoints to invite end users (singly or\nin bulk), list and revoke them, and inspect the effective MCP tool\naccess compiled from their grants, groups, and roles. An end user's\naccess record is an ashare, so editing its grants and suspending it\nuse the `/v1/ashares` routes shared with workspace users. The account\nowner is never an end user: owners already have MCP access without an\nend-user record, the invite refuses the owner's address\n(`owner_self_invite_not_allowed`), and the owner never appears in\nthese lists.\n\n## End user schema\n\n{% openapi-schemas spec=\"enduser\" schemas=\"EndUser\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"EffectiveAccess":{"type":"object","description":"The compiled MCP access for one end user, with source attribution. Access\nis the union of the end user's direct grants, group grants, role grants\n(direct or via groups), and permission sets on the target servers,\nrecompiled on every request.","properties":{"_ashareId":{"type":"string","format":"objectId","readOnly":true,"description":"End-user access-record id this compilation applies to."},"_userId":{"type":"string","format":"objectId","readOnly":true,"description":"The end user's own user id."},"userType":{"type":"string","enum":["end-user"],"description":"Type of the access record the compilation was run for."},"provisionedBy":{"type":"string","enum":["invite","jit"],"description":"How the end-user record was created."},"groups":{"type":"array","description":"Groups that contributed to the compiled access.","items":{"type":"object","properties":{"_id":{"type":"string","format":"objectId","description":"Group id."},"name":{"type":"string","description":"Group name."},"source":{"type":"string","enum":["manual","idp"],"description":"How the end user's membership in this group was created."}}}},"roles":{"type":"array","description":"Roles that contributed to the compiled access.","items":{"type":"object","properties":{"_id":{"type":"string","format":"objectId","description":"Role id."},"name":{"type":"string","description":"Role name."},"via":{"type":"array","description":"Attribution paths through which the role applies, such as `role-direct` or `group:<name>`.","items":{"type":"string"}}}}},"access":{"type":"array","description":"Per-server compiled access, listing the tools the end user can and cannot use.","items":{"type":"object","properties":{"resourceType":{"type":"string","enum":["mcpServer"],"description":"Resource type of the compiled entry."},"_resourceId":{"type":"string","format":"objectId","description":"MCP server this entry applies to."},"resourceName":{"type":["string","null"],"description":"Display name of the MCP server. Null when the server no longer resolves."},"tools":{"type":"array","description":"Tools the end user can invoke on this server.","items":{"type":"object","properties":{"_id":{"type":"string","format":"objectId","description":"Tool id."},"name":{"type":"string","description":"Tool name."},"via":{"type":"array","description":"Source attribution strings such as `direct`, `group:<name>`,\n`pset:<name> (group:<name>)`, `role-direct:<name>`, or\n`role:<name> (group:<name>)`.","items":{"type":"string"}}}}},"deniedTools":{"type":"array","description":"Tools on this server the end user cannot invoke, with the reason.","items":{"type":"object","properties":{"_id":{"type":"string","format":"objectId","description":"Tool id."},"name":{"type":"string","description":"Tool name."},"reason":{"type":"string","description":"Why the tool is not available to this end user."}}}}}}}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"403-forbidden":{"description":"Forbidden. The authenticated caller does not have permission to perform this operation.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/endusers/{_ashareId}/effective-access":{"get":{"summary":"Get an end user's effective access","operationId":"getEndUserEffectiveAccess","tags":["End Users"],"description":"Compiles the end user's effective MCP server tool access with source\nattribution — the union of direct grants, group grants, role grants, and\npermission sets. The result is recomputed on every request rather than\ncached. Requires account owner or administrator access.","parameters":[{"name":"_ashareId","in":"path","required":true,"description":"End-user access-record id (from the end users list).","schema":{"type":"string","format":"objectId"}}],"responses":{"200":{"description":"Compiled effective access with attribution.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EffectiveAccess"}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"403":{"$ref":"#/components/responses/403-forbidden"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
```

## Update an end user's access

> Replaces the end user's group memberships and direct resource grants with\
> the arrays sent. Works on invited end users before they accept. \`disabled\`\
> is not applied here — use \`PUT /v1/ashares/{\_ashareId}/disable\`.\
> \
> An end user's access record is an ashare, so this is the same route as\
> the workspace-user update in the Users API, with this body instead of the\
> workspace fields. \`GET /v1/ashares/{\_id}\` does not return end-user\
> records — read them from \`GET /v1/endusers\`.

```json
{"openapi":"3.2.0","info":{"title":"End Users","version":"1.0.0"},"tags":[{"name":"End Users","description":"End users are people who consume an account's MCP servers without\ngetting workspace access — they sign in through MCP OAuth, optionally\nvia an external IdP. Use these endpoints to invite end users (singly or\nin bulk), list and revoke them, and inspect the effective MCP tool\naccess compiled from their grants, groups, and roles. An end user's\naccess record is an ashare, so editing its grants and suspending it\nuse the `/v1/ashares` routes shared with workspace users. The account\nowner is never an end user: owners already have MCP access without an\nend-user record, the invite refuses the owner's address\n(`owner_self_invite_not_allowed`), and the owner never appears in\nthese lists.\n\n## End user schema\n\n{% openapi-schemas spec=\"enduser\" schemas=\"EndUser\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"EndUserUpdateRequest":{"type":"object","description":"Replacement access for an end user. Both arrays are stored as sent, so\neach must carry every entry to keep, not just the changes.","required":["groupMemberships","resourceGrants"],"properties":{"groupMemberships":{"type":"array","description":"Complete set of groups the end user should belong to after the update.","items":{"$ref":"#/components/schemas/GroupMembership"}},"resourceGrants":{"type":"array","description":"Complete set of direct resource grants the end user should hold after the update.","items":{"$ref":"#/components/schemas/ResourceGrant"}}}},"GroupMembership":{"type":"object","description":"An end user's membership in a group, with the source that created it.","properties":{"_groupId":{"type":"string","format":"objectId","description":"Group the end user belongs to."},"source":{"type":"string","enum":["manual","idp"],"description":"How the membership was created. IdP-synced memberships cannot be\nremoved through the group members API — change the IdP group mapping\ninstead."}}},"ResourceGrant":{"type":"object","description":"Grants access to a resource (currently MCP servers only). A grant names\nthe resource, or applies as a wildcard across all resources of the type,\nand lists the capabilities granted on it.","required":["resourceType","capabilities"],"properties":{"resourceType":{"type":"string","enum":["mcpServer"],"description":"Resource type this grant applies to."},"_resourceId":{"type":["string","null"],"format":"objectId","description":"MCP server this grant applies to. Omit or set to null for a wildcard\ngrant across all MCP servers in the account."},"capabilities":{"type":"array","minItems":1,"description":"Capabilities granted on the target resource.","items":{"type":"string","description":"Capability string. For `mcpServer` grants: `tool:all`,\n`tool:<24-char-hex-id>` (an IO tool `_toolId` or attached prompt `_id`),\n`api:all`, `api:<24-char-hex-apiId>`, or\n`pset:<24-char-hex-permissionSetId>` referencing a permission set\ndefined on the target MCP server."}}}},"EndUser":{"type":"object","description":"An end user's access record in the account. End users authenticate through\nMCP OAuth (optionally via an external IdP) to use MCP servers; they do not\nget workspace access. The `_id` is the access-record id, not the user's own\nid — the user's identity is in `_sharedWithUserId`.","required":["_id"],"properties":{"_id":{"type":"string","format":"objectId","readOnly":true,"description":"Access-record id for this end user in the account."},"_userId":{"type":"string","format":"objectId","readOnly":true,"description":"Account owner's user id."},"_sharedWithUserId":{"type":"string","format":"objectId","readOnly":true,"description":"The end user's own user id."},"userType":{"type":"string","enum":["end-user"],"description":"Distinguishes end-user access records from workspace access records."},"provisionedBy":{"type":"string","enum":["invite","jit"],"description":"How this end-user record was created."},"accepted":{"type":"boolean","description":"When true, the end user has completed invite setup (or was JIT-provisioned)."},"dismissed":{"type":"boolean","description":"When true, the end user has declined the invitation."},"disabled":{"type":"boolean","description":"When true, the end user's access is suspended without deleting the\nrecord. Changed only by `PUT /v1/ashares/{_ashareId}/disable` — a\nvalue sent on the update operation is not applied."},"groupMemberships":{"type":"array","description":"Groups this end user belongs to, with the source of each membership.","items":{"$ref":"#/components/schemas/GroupMembership"}},"resourceGrants":{"type":"array","description":"Direct resource grants on this end user, in addition to any group- or role-derived access.","items":{"$ref":"#/components/schemas/ResourceGrant"}},"_roleIds":{"type":"array","description":"Roles assigned directly to this end user.","items":{"type":"string","format":"objectId"}},"email":{"type":"string","format":"email","readOnly":true,"description":"Email address of the end user, joined from the user record."},"name":{"type":"string","readOnly":true,"description":"Display name of the end user, joined from the user record."},"lastSignIn":{"type":["string","null"],"format":"date-time","readOnly":true,"description":"When the end user last signed in. Null when they have never signed in."},"hasWorkspaceShare":{"type":"boolean","readOnly":true,"description":"When true, the same person also has an active workspace access record on this account."},"createdAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the end-user record was created."},"lastModified":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the end-user record was last updated."}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/ashares/{_ashareId}":{"put":{"summary":"Update an end user's access","operationId":"updateEndUser","tags":["End Users"],"description":"Replaces the end user's group memberships and direct resource grants with\nthe arrays sent. Works on invited end users before they accept. `disabled`\nis not applied here — use `PUT /v1/ashares/{_ashareId}/disable`.\n\nAn end user's access record is an ashare, so this is the same route as\nthe workspace-user update in the Users API, with this body instead of the\nworkspace fields. `GET /v1/ashares/{_id}` does not return end-user\nrecords — read them from `GET /v1/endusers`.","parameters":[{"name":"_ashareId","in":"path","required":true,"description":"End-user access-record id (from the end users list).","schema":{"type":"string","format":"objectId"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EndUserUpdateRequest"}}}},"responses":{"200":{"description":"The updated access record as stored. The identity fields the list\njoins in (`email`, `name`, `lastSignIn`) and `hasWorkspaceShare` are\nnot included, and empty arrays may be omitted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EndUser"}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
```

## Toggle an end user's access

> Toggles the \`disabled\` flag on the end user's access record — call again\
> to restore access; there is no separate \`/enable\` path. Unlike the\
> workspace toggle, this also works on invited end users who have not yet\
> accepted. Shares its route with the workspace-user toggle in the Users\
> API.

```json
{"openapi":"3.2.0","info":{"title":"End Users","version":"1.0.0"},"tags":[{"name":"End Users","description":"End users are people who consume an account's MCP servers without\ngetting workspace access — they sign in through MCP OAuth, optionally\nvia an external IdP. Use these endpoints to invite end users (singly or\nin bulk), list and revoke them, and inspect the effective MCP tool\naccess compiled from their grants, groups, and roles. An end user's\naccess record is an ashare, so editing its grants and suspending it\nuse the `/v1/ashares` routes shared with workspace users. The account\nowner is never an end user: owners already have MCP access without an\nend-user record, the invite refuses the owner's address\n(`owner_self_invite_not_allowed`), and the owner never appears in\nthese lists.\n\n## End user schema\n\n{% openapi-schemas spec=\"enduser\" schemas=\"EndUser\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}}},"schemas":{"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}}},"paths":{"/v1/ashares/{_ashareId}/disable":{"put":{"summary":"Toggle an end user's access","operationId":"toggleEndUserDisabled","tags":["End Users"],"description":"Toggles the `disabled` flag on the end user's access record — call again\nto restore access; there is no separate `/enable` path. Unlike the\nworkspace toggle, this also works on invited end users who have not yet\naccepted. Shares its route with the workspace-user toggle in the Users\nAPI.","parameters":[{"name":"_ashareId","in":"path","required":true,"description":"End-user access-record id (from the end users list).","schema":{"type":"string","format":"objectId"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","description":"Empty body — the target is identified by the path parameter alone."}}}},"responses":{"204":{"description":"End-user access toggled."},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"description":"End user not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://developer.celigo.com/api/api-reference/end-users.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
