> 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/account-and-admin/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, inspect the effective MCP access (tools, APIs, prompts, and resources) compiled from their grants, groups, and roles, and read or delete the `mcpChild` connections that hold the credentials they supplied for connections flagged `requiresEndUserCredentials`. 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. Workspace administrators need no record either: under Celigo OAuth they reach every MCP server in the environment, and everything on it. Other workspace users need an end-user record with grants. Anyone who also holds an end-user record, an administrator included, is judged by that record's grants.

### 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","scim"],"description":"How this end-user record was created. A SCIM push for a person who already has an invited\nor JIT record adopts it in place, so the value can change to `scim` over the record's life.\nFor a SCIM-managed user the identity provider owns the active state and the IdP-sourced\ngroup memberships and roles: `PUT /v1/ashares/{_ashareId}/disable` still toggles `disabled`,\nbut the identity provider's next push re-applies what it holds — deactivate the person or\nchange their groups in the IdP. Direct `resourceGrants` and `manual` memberships are never\ntouched by SCIM."},"externalId":{"type":"string","readOnly":true,"description":"Identifier the identity provider uses for this person in its own directory,\nstored when the record is provisioned through SCIM. Present only when\n`provisionedBy` is `scim`. SCIM matches people by email, not by this value."},"_scimIdpConfigId":{"type":"string","format":"objectId","readOnly":true,"description":"IdP configuration whose SCIM endpoint provisioned this record. Present\nonly when `provisionedBy` is `scim`."},"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 person's group in\nthe identity provider instead (its group mapping, or the SCIM group\nassignment, whichever created the membership)."}}},"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. Each `:all` capability\ncovers only its own kind — grant `tool:all`, `api:all`, `prompt:all`,\nand `resource:all` together to open every item on a server.","items":{"type":"string","pattern":"^(?:tool|api|prompt|resource):(?:[a-fA-F0-9]{24}|all)$|^pset:[a-fA-F0-9]{24}$","description":"Capability string for an `mcpServer` grant. `tool:`, `api:`,\n`prompt:`, and `resource:` take `all` or a 24-hex id on the target\nserver — a `tools[]._toolId` or upstream tool row `_id`, an\n`apis[]._apiId`, a `prompts[]._id`, or a `resources[]._id`; `pset:`\ntakes a `permissionSets[]._id`. Grant prompts with `prompt:<_id>`:\nolder grants written as `tool:<prompt _id>` still validate but are\nnot reported by effective access. Any other shape is rejected with\n400 `validation_failed` (\"Invalid capability\"), and an id that is\nnot attached to the target server with 400 `validation_failed`\nnaming the missing item."}}}}}}}
```

## 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, inspect the effective MCP access\n(tools, APIs, prompts, and resources) compiled from their grants,\ngroups, and roles, and read or delete the `mcpChild` connections that\nhold the credentials they supplied for connections flagged\n`requiresEndUserCredentials`. An end user's access record is an\nashare, so editing its grants and suspending it use the `/v1/ashares`\nroutes shared with workspace users. The account owner is never an end\nuser: owners already have MCP access without an end-user record, the\ninvite refuses the owner's address (`owner_self_invite_not_allowed`),\nand the owner never appears in these lists. Workspace administrators\nneed no record either: under Celigo OAuth they reach every MCP server in\nthe environment, and everything on it. Other workspace users need an\nend-user record with grants. Anyone who also holds an end-user record,\nan administrator included, is judged by that record's grants.\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","scim"],"description":"How this end-user record was created. A SCIM push for a person who already has an invited\nor JIT record adopts it in place, so the value can change to `scim` over the record's life.\nFor a SCIM-managed user the identity provider owns the active state and the IdP-sourced\ngroup memberships and roles: `PUT /v1/ashares/{_ashareId}/disable` still toggles `disabled`,\nbut the identity provider's next push re-applies what it holds — deactivate the person or\nchange their groups in the IdP. Direct `resourceGrants` and `manual` memberships are never\ntouched by SCIM."},"externalId":{"type":"string","readOnly":true,"description":"Identifier the identity provider uses for this person in its own directory,\nstored when the record is provisioned through SCIM. Present only when\n`provisionedBy` is `scim`. SCIM matches people by email, not by this value."},"_scimIdpConfigId":{"type":"string","format":"objectId","readOnly":true,"description":"IdP configuration whose SCIM endpoint provisioned this record. Present\nonly when `provisionedBy` is `scim`."},"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 person's group in\nthe identity provider instead (its group mapping, or the SCIM group\nassignment, whichever created the membership)."}}},"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. Each `:all` capability\ncovers only its own kind — grant `tool:all`, `api:all`, `prompt:all`,\nand `resource:all` together to open every item on a server.","items":{"type":"string","pattern":"^(?:tool|api|prompt|resource):(?:[a-fA-F0-9]{24}|all)$|^pset:[a-fA-F0-9]{24}$","description":"Capability string for an `mcpServer` grant. `tool:`, `api:`,\n`prompt:`, and `resource:` take `all` or a 24-hex id on the target\nserver — a `tools[]._toolId` or upstream tool row `_id`, an\n`apis[]._apiId`, a `prompts[]._id`, or a `resources[]._id`; `pset:`\ntakes a `permissionSets[]._id`. Grant prompts with `prompt:<_id>`:\nolder grants written as `tool:<prompt _id>` still validate but are\nnot reported by effective access. Any other shape is rejected with\n400 `validation_failed` (\"Invalid capability\"), and an id that is\nnot attached to the target server with 400 `validation_failed`\nnaming the missing item."}}}},"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, inspect the effective MCP access\n(tools, APIs, prompts, and resources) compiled from their grants,\ngroups, and roles, and read or delete the `mcpChild` connections that\nhold the credentials they supplied for connections flagged\n`requiresEndUserCredentials`. An end user's access record is an\nashare, so editing its grants and suspending it use the `/v1/ashares`\nroutes shared with workspace users. The account owner is never an end\nuser: owners already have MCP access without an end-user record, the\ninvite refuses the owner's address (`owner_self_invite_not_allowed`),\nand the owner never appears in these lists. Workspace administrators\nneed no record either: under Celigo OAuth they reach every MCP server in\nthe environment, and everything on it. Other workspace users need an\nend-user record with grants. Anyone who also holds an end-user record,\nan administrator included, is judged by that record's grants.\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. Each `:all` capability\ncovers only its own kind — grant `tool:all`, `api:all`, `prompt:all`,\nand `resource:all` together to open every item on a server.","items":{"type":"string","pattern":"^(?:tool|api|prompt|resource):(?:[a-fA-F0-9]{24}|all)$|^pset:[a-fA-F0-9]{24}$","description":"Capability string for an `mcpServer` grant. `tool:`, `api:`,\n`prompt:`, and `resource:` take `all` or a 24-hex id on the target\nserver — a `tools[]._toolId` or upstream tool row `_id`, an\n`apis[]._apiId`, a `prompts[]._id`, or a `resources[]._id`; `pset:`\ntakes a `permissionSets[]._id`. Grant prompts with `prompt:<_id>`:\nolder grants written as `tool:<prompt _id>` still validate but are\nnot reported by effective access. Any other shape is rejected with\n400 `validation_failed` (\"Invalid capability\"), and an id that is\nnot attached to the target server with 400 `validation_failed`\nnaming the missing item."}}}},"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`. A revoked record doesn't count:\ninviting that address again creates a new record, with none of the\nold record's groups or grants.","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, inspect the effective MCP access\n(tools, APIs, prompts, and resources) compiled from their grants,\ngroups, and roles, and read or delete the `mcpChild` connections that\nhold the credentials they supplied for connections flagged\n`requiresEndUserCredentials`. An end user's access record is an\nashare, so editing its grants and suspending it use the `/v1/ashares`\nroutes shared with workspace users. The account owner is never an end\nuser: owners already have MCP access without an end-user record, the\ninvite refuses the owner's address (`owner_self_invite_not_allowed`),\nand the owner never appears in these lists. Workspace administrators\nneed no record either: under Celigo OAuth they reach every MCP server in\nthe environment, and everything on it. Other workspace users need an\nend-user record with grants. Anyone who also holds an end-user record,\nan administrator included, is judged by that record's grants.\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. Each `:all` capability\ncovers only its own kind — grant `tool:all`, `api:all`, `prompt:all`,\nand `resource:all` together to open every item on a server.","items":{"type":"string","pattern":"^(?:tool|api|prompt|resource):(?:[a-fA-F0-9]{24}|all)$|^pset:[a-fA-F0-9]{24}$","description":"Capability string for an `mcpServer` grant. `tool:`, `api:`,\n`prompt:`, and `resource:` take `all` or a 24-hex id on the target\nserver — a `tools[]._toolId` or upstream tool row `_id`, an\n`apis[]._apiId`, a `prompts[]._id`, or a `resources[]._id`; `pset:`\ntakes a `permissionSets[]._id`. Grant prompts with `prompt:<_id>`:\nolder grants written as `tool:<prompt _id>` still validate but are\nnot reported by effective access. Any other shape is rejected with\n400 `validation_failed` (\"Invalid capability\"), and an id that is\nnot attached to the target server with 400 `validation_failed`\nnaming the missing item."}}}},"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; by the platform contract the \`mcpChild\` connections the end\
> user holds on the account are invalidated with it. 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, inspect the effective MCP access\n(tools, APIs, prompts, and resources) compiled from their grants,\ngroups, and roles, and read or delete the `mcpChild` connections that\nhold the credentials they supplied for connections flagged\n`requiresEndUserCredentials`. An end user's access record is an\nashare, so editing its grants and suspending it use the `/v1/ashares`\nroutes shared with workspace users. The account owner is never an end\nuser: owners already have MCP access without an end-user record, the\ninvite refuses the owner's address (`owner_self_invite_not_allowed`),\nand the owner never appears in these lists. Workspace administrators\nneed no record either: under Celigo OAuth they reach every MCP server in\nthe environment, and everything on it. Other workspace users need an\nend-user record with grants. Anyone who also holds an end-user record,\nan administrator included, is judged by that record's grants.\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; by the platform contract the `mcpChild` connections the end\nuser holds on the account are invalidated with it. Any workspace access\nrecord the same person holds is unaffected. Requires account owner or\nadministrator 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 access — tools, APIs,\
> prompts, and file resources — 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, inspect the effective MCP access\n(tools, APIs, prompts, and resources) compiled from their grants,\ngroups, and roles, and read or delete the `mcpChild` connections that\nhold the credentials they supplied for connections flagged\n`requiresEndUserCredentials`. An end user's access record is an\nashare, so editing its grants and suspending it use the `/v1/ashares`\nroutes shared with workspace users. The account owner is never an end\nuser: owners already have MCP access without an end-user record, the\ninvite refuses the owner's address (`owner_self_invite_not_allowed`),\nand the owner never appears in these lists. Workspace administrators\nneed no record either: under Celigo OAuth they reach every MCP server in\nthe environment, and everything on it. Other workspace users need an\nend-user record with grants. Anyone who also holds an end-user record,\nan administrator included, is judged by that record's grants.\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","scim"],"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 (same rule as `GroupMembership.source` on the end-user record)."}}}},"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, APIs, prompts, and\nfile resources the end user can and cannot use. Disabled items never\nappear on either side.","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":{"$ref":"#/components/schemas/DeniedItem"}},"apis":{"type":"array","description":"Builder-mode APIs the end user can invoke on this server,\ngranted via `api:<id>`, `api:all`, or a permission set's\n`_apiIds`.","items":{"$ref":"#/components/schemas/GrantedItem"}},"deniedApis":{"type":"array","description":"Enabled APIs on this server the end user cannot invoke, with the reason.","items":{"$ref":"#/components/schemas/DeniedItem"}},"prompts":{"type":"array","description":"Prompts the end user can fetch on this server, granted via\n`prompt:<id>`, `prompt:all`, or a permission set's `_promptIds`.","items":{"$ref":"#/components/schemas/GrantedItem"}},"deniedPrompts":{"type":"array","description":"Enabled prompts on this server the end user cannot fetch, with the reason.","items":{"$ref":"#/components/schemas/DeniedItem"}},"resources":{"type":"array","description":"File resources the end user can read on this server, granted via\n`resource:<id>`, `resource:all`, or a permission set's\n`_resourceIds`. `name` carries the resource `title`.","items":{"$ref":"#/components/schemas/GrantedItem"}},"deniedResources":{"type":"array","description":"Enabled resources on this server the end user cannot read, with the reason.","items":{"$ref":"#/components/schemas/DeniedItem"}}}}}}},"DeniedItem":{"type":"object","description":"One enabled item on the server that the end user's grants do not reach.","properties":{"_id":{"type":"string","format":"objectId","description":"Item id — a `tools[]._toolId`, `apis[]._apiId`, `prompts[]._id`, or `resources[]._id` on the server."},"name":{"type":"string","description":"Item name as exposed on this server (the `title` for a resource)."},"reason":{"type":"string","description":"Why the item is not available to this end user — `Not in any granted\npermission set or <kind> grant`, where `<kind>` is `tool`, `api`,\n`prompt`, or `resource`."}}},"GrantedItem":{"type":"object","description":"One granted API, prompt, or resource with the grant paths that produced it.","properties":{"_id":{"type":"string","format":"objectId","description":"Item id — an `apis[]._apiId`, `prompts[]._id`, or `resources[]._id` on the server."},"name":{"type":"string","description":"Item name as exposed on this server (the `title` for a resource)."},"via":{"type":"array","description":"Source attribution strings such as `direct`, `group:<name>`,\n`pset:<name> (direct)`, `pset:<name> (group:<name>)`,\n`role-direct:<name>`, or `role:<name> (group:<name>)`.","items":{"type":"string"}}}},"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 access — tools, APIs,\nprompts, and file resources — with source attribution: the union of\ndirect grants, group grants, role grants, and permission sets. The\nresult is recomputed on every request rather than cached. Requires\naccount 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"}}}}}}
```

## Get an end user's connection

> Returns one \`mcpChild\` connection — the credentials an end user supplied\
> for a connection that an MCP server flagged \`requiresEndUserCredentials\`.\
> Credentials are masked as on every connection read; there is no unmasked\
> form. Only children resolve here: a standard connection id answers 404\
> exactly like an unknown id, and the generic \`GET /v1/connections/{\_id}\`\
> answers 404 for a child. No MCP server appears in the path because a\
> child is keyed by its parent connection and end user, not by server —\
> discover ids with \`GET /v1/mcpservers/{\_id}/connections?connectionRole=mcpChild\`.\
> On the returned document \`\_userId\` is the end user who owns it and\
> \`\_mcpOwnerId\` is the account. 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, inspect the effective MCP access\n(tools, APIs, prompts, and resources) compiled from their grants,\ngroups, and roles, and read or delete the `mcpChild` connections that\nhold the credentials they supplied for connections flagged\n`requiresEndUserCredentials`. An end user's access record is an\nashare, so editing its grants and suspending it use the `/v1/ashares`\nroutes shared with workspace users. The account owner is never an end\nuser: owners already have MCP access without an end-user record, the\ninvite refuses the owner's address (`owner_self_invite_not_allowed`),\nand the owner never appears in these lists. Workspace administrators\nneed no record either: under Celigo OAuth they reach every MCP server in\nthe environment, and everything on it. Other workspace users need an\nend-user record with grants. Anyone who also holds an end-user record,\nan administrator included, is judged by that record's grants.\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":{"Connection":{"type":"object","required":["_id","name","type","createdAt","lastModified"],"description":"Connection object as returned by the API.","allOf":[{"$ref":"#/components/schemas/ResponseBase"},{"type":"object","properties":{"netsuite":{"description":"Present when `type` is `netsuite`.","allOf":[{"$ref":"#/components/schemas/NetSuite"},{"type":"object","properties":{"suiteAppInstalled":{"type":"boolean","readOnly":true,"description":"When true, the Celigo integrator.io SuiteApp (SuiteScript 2.x) was detected in\nthe connected NetSuite account the last time the connection authenticated. It\nsays nothing about the legacy Celigo bundle; for a live check of both, use\n`GET /v1/connections/{_id}/distributedApps`."}}}]},"salesforce":{"description":"Present when `type` is `salesforce`.","allOf":[{"$ref":"#/components/schemas/Salesforce"},{"type":"object","properties":{"info":{"type":"object","readOnly":true,"description":"Salesforce org and user metadata populated by the server after a successful\nauthentication (the OpenID Connect userinfo of the authorizing user). Read-only.","properties":{"user_id":{"type":"string","readOnly":true,"description":"Salesforce user ID of the authorizing user."},"organization_id":{"type":"string","readOnly":true,"description":"Salesforce organization (org) ID this connection authenticates to."},"email":{"type":"string","format":"email","readOnly":true,"description":"Email address of the authorizing Salesforce user."},"preferred_username":{"type":"string","readOnly":true,"description":"Salesforce login username of the authorizing user."},"name":{"type":"string","readOnly":true,"description":"Full display name of the authorizing user."},"is_salesforce_integration_user":{"type":"boolean","readOnly":true,"description":"When true, the authorizing user is a Salesforce Integration User license."}}}}}]},"ftp":{"description":"Present when `type` is `ftp`.","allOf":[{"$ref":"#/components/schemas/FTP"}]},"s3":{"description":"Present when `type` is `s3`.","allOf":[{"$ref":"#/components/schemas/S3"}]},"http":{"description":"Present when `type` is `http`.","allOf":[{"$ref":"#/components/schemas/HTTP"}]},"rdbms":{"description":"Present when `type` is `rdbms`.","allOf":[{"$ref":"#/components/schemas/RDBMS"}]},"mongodb":{"description":"Present when `type` is `mongodb`.","allOf":[{"$ref":"#/components/schemas/MongoDB"}]},"as2":{"description":"Present when `type` is `as2`.","allOf":[{"$ref":"#/components/schemas/AS2"}]},"filesystem":{"description":"Present when `type` is `filesystem`.","allOf":[{"$ref":"#/components/schemas/Filesystem"}]},"mcp":{"description":"Present when `type` is `mcp`.","allOf":[{"$ref":"#/components/schemas/MCP"}]},"dynamodb":{"description":"Present when `type` is `dynamodb`.","allOf":[{"$ref":"#/components/schemas/DynamoDB"}]},"jdbc":{"description":"Present when `type` is `jdbc`.","allOf":[{"$ref":"#/components/schemas/JDBC"}]},"van":{"description":"Present when `type` is `van`.","allOf":[{"$ref":"#/components/schemas/VAN"}]},"wrapper":{"description":"Present when `type` is `wrapper`.","allOf":[{"$ref":"#/components/schemas/Wrapper"}]}}}],"if":{"properties":{"type":{"const":"netsuite"}},"required":["type"]},"then":{"required":["netsuite"]},"else":{"if":{"properties":{"type":{"const":"salesforce"}},"required":["type"]},"then":{"required":["salesforce"]},"else":{"if":{"properties":{"type":{"const":"ftp"}},"required":["type"]},"then":{"required":["ftp"]},"else":{"if":{"properties":{"type":{"const":"s3"}},"required":["type"]},"then":{"required":["s3"]},"else":{"if":{"properties":{"type":{"const":"http"}},"required":["type"]},"then":{"required":["http"]},"else":{"if":{"properties":{"type":{"const":"rdbms"}},"required":["type"]},"then":{"required":["rdbms"]},"else":{"if":{"properties":{"type":{"const":"mongodb"}},"required":["type"]},"then":{"required":["mongodb"]},"else":{"if":{"properties":{"type":{"const":"as2"}},"required":["type"]},"then":{"required":["as2"]},"else":{"if":{"properties":{"type":{"const":"filesystem"}},"required":["type"]},"then":{"required":["filesystem"]},"else":{"if":{"properties":{"type":{"const":"mcp"}},"required":["type"]},"then":{"required":["mcp"]},"else":{"if":{"properties":{"type":{"const":"dynamodb"}},"required":["type"]},"then":{"required":["dynamodb"]},"else":{"if":{"properties":{"type":{"const":"jdbc"}},"required":["type"]},"then":{"required":["jdbc"]},"else":{"if":{"properties":{"type":{"const":"van"}},"required":["type"]},"then":{"required":["van"]},"else":{"if":{"properties":{"type":{"const":"wrapper"}},"required":["type"]},"then":{"required":["wrapper"]},"else":{"if":{"properties":{"type":{"const":"rest"}},"required":["type"]},"then":{"required":["rest"]}}}}}}}}}}}}}}}},"ResponseBase":{"type":"object","description":"Shared properties present on every connection response regardless of type.","allOf":[{"$ref":"#/components/schemas/ResourceResponse"},{"$ref":"#/components/schemas/IAResourceResponse"},{"type":"object","properties":{"name":{"type":"string","description":"Display name for the connection.","maxLength":100},"type":{"type":"string","description":"The type of connection determining which authentication and connectivity options are available","enum":["netsuite","salesforce","ftp","s3","wrapper","http","rdbms","mongodb","as2","filesystem","mcp","dynamodb","jdbc","van","rest"]},"externalId":{"type":"string","description":"External identifier for the connection, often used for integration with third-party systems"},"assistant":{"type":"string","description":"Application name in lowercase for HTTP connections to systems with integrator.io adaptors.\nUsed to identify the target application being connected to.\nExamples - Shopify: \"shopify\", eBay: \"ebay\".\nOnly applicable for HTTP connection types.\n"},"_agentId":{"type":"string","format":"objectId","description":"Reference to a Celigo on-premise Agent. Required for connection types that need\nlocal network or filesystem access (JDBC, filesystem, Oracle RDBMS, and on-premise MongoDB).\nThe agent establishes a secure tunnel between the on-premise environment and integrator.io.\n"},"_borrowConcurrencyFromConnectionId":{"type":"string","format":"objectId","description":"Reference to another connection to share concurrency limits with. When set, this\nconnection's traffic counts against the referenced connection's limit instead of its own,\nand its own concurrency and auto-recovery settings have no effect. One level only: the\nreferenced connection may not itself borrow, and a connection that others borrow from\ncannot start borrowing. A connection cannot reference itself (422)."},"debugDate":{"type":"string","format":"date-time","description":"Date until which debug logging is enabled for this connection"},"settingsForm":{"type":"object","description":"Dynamic form configuration for connection-specific settings"},"settings":{"type":"object","description":"Connection-specific settings and configurations"},"pgp":{"description":"Present for file-based connections (ftp, s3, filesystem, …) that encrypt or decrypt files with PGP.","allOf":[{"$ref":"#/components/schemas/PGP"}]},"ssl":{"$ref":"#/components/schemas/SSL"},"aiDescription":{"$ref":"#/components/schemas/AIDescription"},"offline":{"type":"boolean","description":"When true, the connection has been taken offline and is skipped during flow execution.\nIt is set by the connection test a create or `PUT` runs: the result arrives in the\nwrite's response or, when the target is slow to answer, shortly afterwards (the audit\nlog records a `system` change; `lastModified` doesn't move), so read it again a few\nseconds after the write. On an `http` connection the write runs the test only when\n`http.ping` is configured, and an `http` connection that was never tested has no\n`offline` key.","readOnly":true},"needsAuthorization":{"type":"boolean","readOnly":true,"description":"OAuth handshake state. Celigo's OAuth callback sets it to `false` once the user consents\nand the tokens are stored (see `GET /v1/connection/{_id}/oauth2`). A connection that\nwas never authorized usually has no `needsAuthorization` key, so its absence does not\nmean the connection is authorized."},"_sourceId":{"type":"string","format":"objectId","description":"Source connection this was cloned from.","readOnly":true},"connectionRole":{"type":"string","enum":["standard","mcpChild"],"readOnly":true,"description":"Distinguishes account-owned connections from the per-end-user credential copies\nMCP servers collect. Absent on connections last saved before the field existed,\nwhich behave as `standard`. Sending `mcpChild` on `POST` or `PUT /v1/connections`\nfails with 422 `mcp_child_generic_route_not_allowed`, and `/connectionRole` is not a\npatchable path; child connections are written only by the MCP end-user setup page,\nnever through `/v1`."},"endUserProvidedFields":{"type":"array","items":{"type":"string"},"description":"Dot-paths of this connection's fields (for example `http.encrypted.apiKey` or\n`rdbms.user`) that each MCP end user must supply on their own `mcpChild` copy instead\nof inheriting the parent's value. Only returned on a `standard` connection that has\npaths set; never returned on a child. Writable through `POST`, `PUT`, and `PATCH`;\nby the platform contract, a write that changes the list invalidates the children end\nusers already hold against this parent."},"_parentConnectionId":{"type":"string","format":"objectId","readOnly":true,"description":"Parent connection this child copies its non-credential configuration from. Present\nonly when `connectionRole` is `mcpChild`; set by the end-user setup page and ignored\nwhen sent on a standard connection."},"_mcpOwnerId":{"type":"string","format":"objectId","readOnly":true,"description":"Account owner whose parent connection and MCP servers this child belongs to. Present\nonly when `connectionRole` is `mcpChild`; on a child, `_userId` is the end user and\nthis field is the account."},"_parentSyncedAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the child's non-credential fields were last synced from the parent\nconnection. Present only when `connectionRole` is `mcpChild`."},"_userId":{"type":"string","format":"objectId","description":"End user who owns this `mcpChild` connection's credentials. Present only when\n`connectionRole` is `mcpChild`; a standard connection belongs to the account and\nomits this field.","readOnly":true},"debugUntil":{"type":"string","format":"date-time","description":"Debug logging is active until this timestamp. Absent or in the past means debug is off.","readOnly":true},"encrypted":{"type":"string","description":"Masked placeholder for encrypted credential fields. Always returns `\"******\"`.","readOnly":true},"isHTTP":{"type":"boolean","description":"When true, the connection uses the HTTP adaptor internally, even when `type` is `wrapper`.","readOnly":true},"autoRecoverRateLimitErrors":{"type":"boolean","default":true,"description":"When true, rate-limit errors from the target system trigger automatic recovery: concurrency\ndrops to 1, the rate-limited requests are retried with doubling waits (1 to 1024 minutes,\nafter which the flag switches itself off), and concurrency climbs back toward\n`targetConcurrencyLevel`. While true, `targetConcurrencyLevel` is the throughput lever: a\n`concurrencyLevel` sent in a PUT is ignored, and one sent in a PATCH is stored but the\nrecovery machinery moves it back toward the target. Recovery never runs on `ftp`\nconnections: FTP errors aren't treated as rate limits."},"enableMicroBatchForOneToMany":{"type":"boolean","default":true,"description":"When true, enables micro-batching for one-to-many data flows through this connection."},"enableCsvObjectParsing":{"type":"boolean","default":true,"description":"When true, enables CSV-to-object parsing for data received through this connection."},"microServices":{"type":"object","description":"Per-adaptor feature flags controlling which microservice workers handle this connection's traffic.","readOnly":true,"properties":{"disableHttp":{"type":"boolean","description":"When true, the HTTP microservice worker is disabled for this connection."},"disableNetSuiteDistributed":{"type":"boolean","description":"When true, the NetSuite distributed-processing worker is disabled for this connection."},"disableNetSuiteProxy":{"type":"boolean","description":"When true, the NetSuite proxy worker is disabled for this connection."},"disableNetSuiteWebservices":{"type":"boolean","description":"When true, the NetSuite SuiteTalk Web Services worker is disabled for this connection."},"disableRdbms":{"type":"boolean","description":"When true, the RDBMS worker is disabled for this connection."},"disableAs2":{"type":"boolean","description":"When true, the AS2 worker is disabled for this connection."},"disableAs2File":{"type":"boolean","description":"When true, the AS2 file-processing worker is disabled for this connection."},"disableDataLoaderFile":{"type":"boolean","description":"When true, the data-loader file worker is disabled for this connection."},"disableFtp":{"type":"boolean","description":"When true, the FTP worker is disabled for this connection."},"disableS3":{"type":"boolean","description":"When true, the S3 worker is disabled for this connection."},"disableSalesforce":{"type":"boolean","description":"When true, the Salesforce worker is disabled for this connection."},"disableFile":{"type":"boolean","description":"When true, the generic file worker is disabled for this connection."},"disableNsFile":{"type":"boolean","description":"When true, the NetSuite file worker is disabled for this connection."},"workerGroup":{"type":"string","description":"Name of the worker group that processes this connection's traffic."}}},"queues":{"type":"array","description":"Message queue sizes for this connection. Always present on GET-by-ID; on the list endpoint only when `fetchQueueSize=true`.","readOnly":true,"items":{"type":"object","properties":{"name":{"type":"string","description":"Queue identifier (typically the connection ID)."},"size":{"type":"integer","description":"Number of messages currently in the queue."}}}}}}]},"ResourceResponse":{"type":"object","description":"Response","properties":{"_id":{"type":"string","format":"objectId","readOnly":true,"description":"Unique identifier for the resource. Format is a 24-character hexadecimal string."},"createdAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the resource was created. Set automatically and cannot be modified."},"lastModified":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the resource was last updated. Changes whenever any property is modified."},"deletedAt":{"type":["string","null"],"format":"date-time","readOnly":true,"description":"Timestamp when the resource was soft-deleted. When null or absent, the resource is active."}},"required":["_id"]},"IAResourceResponse":{"type":"object","description":"Integration app response fields for resources that are part of integration apps","properties":{"_integrationId":{"type":"string","format":"objectId","readOnly":true,"description":"Reference to the specific integration instance that contains this resource.\n\nThis field is only populated for resources that are part of an integration app\ninstallation. It contains the unique identifier (_id) of the integration\nresource that was installed in the account.\n\nThe integration instance represents a specific installed instance of an\nintegration app, with its own configuration, settings, and runtime environment.\n\nThis reference enables:\n- Tracing the resource back to its parent integration instance\n- Permission and access control based on integration ownership\n- Lifecycle management (enabling/disabling, updating, or uninstalling)\n"},"_connectorId":{"type":"string","format":"objectId","readOnly":true,"description":"Integration App (connector) that defines this resource. Present only on resources an\nIntegration App owns. The app locks parts of these documents, and a PUT that changes a\nlocked field answers 200 but keeps the stored value, so read the document back to confirm\na change."}}},"PGP":{"type":"object","description":"PGP encryption settings for file-based connections (ftp, s3, and similar). When set, files are\nPGP-encrypted before upload and/or decrypted after download. Supply at least one of `publicKey`\n(to encrypt outbound files) or `privateKey` (to decrypt inbound files); set `passphrase` whenever\n`privateKey` is provided.","properties":{"publicKey":{"type":"string","description":"ASCII-armored PGP public key used to encrypt outbound files before upload.\nSet this when the connection sends encrypted files; omit it for decrypt-only connections."},"privateKey":{"type":"string","writeOnly":true,"description":"ASCII-armored PGP private key used to decrypt inbound files after download (encrypted at rest;\nreturned masked as `\"******\"`). Set this when the connection receives encrypted files."},"passphrase":{"type":"string","writeOnly":true,"description":"Passphrase that unlocks `privateKey` (encrypted at rest; returned masked as `\"******\"`). Set this whenever `privateKey` is provided."},"compressionAlgorithm":{"type":"string","enum":["zip","zlib"],"description":"Compression applied to the message payload before PGP encryption. Match the algorithm the recipient expects; leave unset to use the server default."},"asciiArmored":{"type":"boolean","default":true,"description":"When true, produces ASCII-armored (text) PGP output. Set to false only when the recipient requires binary PGP output."}},"if":{"required":["privateKey"]},"then":{"required":["passphrase"]}},"SSL":{"type":"object","description":"SSL/TLS certificate configuration for database connections that use client certificate\n(mTLS) authentication or connect to servers with private CA-signed certificates. Provide\ncert and key together for mTLS, ca for a private CA, and passphrase only when the private\nkey is encrypted; cert/key and ca can be combined.","properties":{"ca":{"type":"string","description":"Certificate Authority certificate in PEM format. Set when the database server uses a\ncertificate signed by a private CA not in the system's default trust store.","writeOnly":true},"key":{"type":"string","description":"Client private key in PEM format, paired with cert for mTLS authentication.\nCannot be provided without cert.","writeOnly":true},"passphrase":{"type":"string","description":"Passphrase that decrypts the private key in the key field, when that key is password-protected.","writeOnly":true},"cert":{"type":"string","description":"Client certificate in PEM format, paired with key for mTLS authentication.\nCannot be provided without key.","writeOnly":true}}},"AIDescription":{"type":"object","description":"AI-generated descriptions and documentation for the resource.\n\nThis object contains automatically generated content that helps users\nunderstand the purpose, behavior, and configuration of the resource without\nrequiring them to analyze the technical details. The AI-generated content\nis sanitized and safe for display in the UI.\n","properties":{"summary":{"type":["string","null"],"description":"Brief AI-generated summary of the resource's purpose and functionality.\n\nThis concise description provides a quick overview of what the resource does,\nwhat systems it interacts with, and its primary role in the integration.\nThe summary is suitable for display in list views, dashboards, and other\ncontexts where space is limited.\n\nMaximum length: 10KB\n"},"detailed":{"type":["string","null"],"description":"Comprehensive AI-generated description of the resource's functionality.\n\nThis detailed explanation covers the resource's purpose, configuration details,\ndata flow patterns, filtering logic, and other technical aspects. It provides\nin-depth information suitable for documentation, tooltips, or detailed views\nin the administration interface.\n\nThe content may include HTML formatting for improved readability.\n\nMaximum length: 10KB\n"},"generatedOn":{"type":["string","null"],"format":"date-time","description":"Timestamp indicating when the AI description was generated.\n\nThis field helps track the freshness of the AI-generated content and\ndetermine when it might need to be regenerated due to changes in the\nresource's configuration or behavior.\n\nThe timestamp is recorded in ISO 8601 format with UTC timezone (Z suffix).\n"}}},"NetSuite":{"type":"object","description":"Configuration for NetSuite ERP connections. Used when the connection type is \"netsuite\".\nThe authType field selects the authentication method; token-based authentication (TBA) is\nrecommended for production.","required":["authType"],"properties":{"authType":{"type":"string","enum":["token","token-auto"],"description":"Authentication method for the NetSuite connection. token-auto delegates the token\nlifecycle to an iClient; token uses a manually-supplied tokenId/tokenSecret pair."},"account":{"type":"string","description":"NetSuite account ID (automatically uppercased), required for token and token-auto authentication.\nFound in NetSuite under Setup > Company > Company Information. Non-production accounts\ncarry an environment suffix (e.g. `123456_SB1`); production and beta use the bare id."},"environment":{"type":"string","enum":["production","sandbox","sandbox2.0","beta"],"description":"NetSuite environment to connect to. Defaults to production when not specified."},"tokenId":{"type":"string","description":"NetSuite TBA token ID (encrypted at rest). Required when authType is \"token\".\n\nGenerated in NetSuite under Setup > Users/Roles > Access Tokens.\nMust be paired with the corresponding tokenSecret.\n","writeOnly":true},"tokenSecret":{"type":"string","description":"NetSuite TBA token secret (encrypted at rest). Required when authType is \"token\".\n\nGenerated alongside the tokenId in NetSuite. Treat as a sensitive credential.\n","writeOnly":true},"entityId":{"type":"string","description":"NetSuite entity/user ID associated with the token."},"tokenName":{"type":"string","description":"Human-readable name of the NetSuite access token for identification purposes."},"roleId":{"type":"string","description":"NetSuite role ID that determines the permissions for this connection.\n\nThe role controls which records, fields, and operations are accessible.\nMust match the role associated with the access token in NetSuite.\n"},"requestLevelCredentials":{"type":"boolean","default":false,"description":"When true, authentication credentials are sent with each individual API request\nrather than maintaining a persistent session. The connection form sets this to true\nfor token (manual TBA) authentication.\n"},"dataCenterURLs":{"type":"object","description":"NetSuite data center URLs for the account, auto-discovered from the account ID.\nThese are populated by the server after a successful connection.\n","readOnly":true,"properties":{"restDomain":{"type":"string","description":"Base URL for the account's RESTlet and REST API endpoints."},"webservicesDomain":{"type":"string","description":"Base URL for the account's SuiteTalk (SOAP) web services endpoints."},"systemDomain":{"type":"string","description":"Base URL for the account's NetSuite UI/system endpoints."}}},"accountName":{"type":"string","description":"Human-readable NetSuite account name (display purposes only)."},"roleName":{"type":"string","description":"Human-readable name of the NetSuite role (display purposes only)."},"wsdlVersion":{"type":"string","description":"SuiteTalk Web Services WSDL version. The API stores only `latest` or `next`; any other value sent\non create or update is normalized to one of these (the connection form's \"2025.1\" maps to `latest`\nand \"2023.1\" maps to `next`; unrecognized version strings fall back to `latest`). Defaults to\n`latest`, which requires Token-Based Authentication.","enum":["latest","next"],"default":"latest"},"applicationId":{"type":"string","description":"NetSuite application ID from the integration record.\nRequired for some authentication configurations to identify the calling application.\n"},"concurrencyLevel":{"type":"integer","description":"Maximum number of requests this connection sends to NetSuite in parallel, across SOAP,\nREST and RESTlet calls. Send no more than the integrator.io license ceiling (25 standard,\n50 with an Environments license). NetSuite separately enforces one\nconcurrency limit per NetSuite account that every caller of its SOAP, REST and RESTlet\nAPIs shares — all integrator.io connections to that account and every other client\ncalling those APIs from outside integrator.io (other integrations, third-party tools).","minimum":1,"maximum":50,"default":5},"targetConcurrencyLevel":{"type":"integer","description":"Target concurrency level for auto-scaling. The system adjusts concurrency\nbetween 1 and this value based on rate limit and governance feedback.","minimum":1,"maximum":50,"default":5},"_iClientId":{"type":"string","format":"objectId","description":"ID of the iClient used for token-based authentication."}}},"Salesforce":{"type":"object","description":"Configuration for Salesforce CRM connections. Used when the connection type is \"salesforce\".\nAuthenticates via OAuth 2.0: oauth2FlowType \"jwtBearerToken\" does server-to-server auth\nthrough a Connected App (recommended for automation), while \"refreshToken\" uses an\ninteractive browser authorization for user-context integrations.","required":["oauth2FlowType","sandbox"],"properties":{"sandbox":{"type":"boolean","description":"Whether this connection targets a Salesforce non-production (sandbox) org. When true,\nauthenticates against test.salesforce.com instead of login.salesforce.com. Must match\nthe actual Salesforce org type or authentication fails. This is the form's\nproduction-vs-sandbox selector (distinct from the connection-level `sandbox` flag).","default":false},"oauth2FlowType":{"type":"string","enum":["jwtBearerToken","refreshToken"],"description":"OAuth 2.0 authentication flow type. Use jwtBearerToken for automated server-to-server\nintegrations (requires a Connected App with a digital certificate and the username field).\nUse refreshToken for integrations that operate in a specific user's context. Defaults to\nrefreshToken when omitted.","default":"refreshToken"},"username":{"type":"string","description":"Salesforce login username (email) of the user whose permissions the integration operates\nunder. Used by the jwtBearerToken flow to identify the subject of the assertion."},"_iClientId":{"type":"string","format":"objectId","description":"Reference to the iClient holding your own Salesforce Connected App's client ID and secret.\nSet this to authenticate through a custom Connected App; omit it to use Celigo's\npre-configured Connected App."},"baseURI":{"type":"string","format":"uri","description":"Salesforce instance URL for this org (e.g. \"https://mycompany.my.salesforce.com\").\nAuto-discovered and populated during OAuth authentication; set it explicitly only to\nforce a specific instance URL."},"bearerToken":{"type":"string","writeOnly":true,"description":"OAuth access token for Salesforce API calls (encrypted at rest; returned masked as\n`\"******\"`). Auto-managed by the system during the OAuth flow; rarely set manually."},"refreshToken":{"type":"string","writeOnly":true,"description":"OAuth refresh token used to mint new access tokens (encrypted at rest; returned masked as\n`\"******\"`). Obtained during the initial browser-based authorization of the refreshToken\nflow; auto-managed by the system."},"packagedOAuth":{"type":"boolean","description":"When true, the connection uses Celigo's pre-configured (packaged) Connected App. Set by\nthe system based on whether a custom `_iClientId` is supplied and the OAuth flow completed;\nnot reliably honored when supplied in the request body."},"scope":{"type":"array","items":{"type":"string"},"description":"OAuth scopes requested during authorization. Scope values are defined by Salesforce — `full`\ngrants complete API access and `refresh_token` enables long-lived refresh tokens. Defaults\nto `full` and `refresh_token` when omitted. A saved empty array is the normal stored state:\nthe connection form does not expose this field, and every save from the connection editor\nresets values written through the API.","default":["full","refresh_token"]},"concurrencyLevel":{"type":"integer","description":"Maximum number of concurrent API requests to Salesforce. Salesforce enforces per-org API\nrequest limits, so setting this high consumes the org's API call allocation faster. Send no\nmore than the account's licensed ceiling.","minimum":1,"maximum":50,"default":5},"targetConcurrencyLevel":{"type":"integer","description":"Upper bound for auto-scaling concurrency. When automatic rate-limit recovery is enabled, the\nsystem adjusts concurrency between 1 and this value based on rate-limit feedback from\nSalesforce. Send no more than the account's licensed ceiling.","minimum":1,"maximum":50,"default":5}},"if":{"properties":{"oauth2FlowType":{"const":"jwtBearerToken"}},"required":["oauth2FlowType"]},"then":{"required":["username"]}},"FTP":{"type":"object","description":"Configuration for FTP/SFTP/FTPS file transfer connections. Used when the connection type is \"ftp\".\nThe type field selects the transfer protocol, which determines port defaults and available auth methods.","required":["type","hostURI","username"],"properties":{"type":{"type":"string","enum":["ftp","sftp","ftps"],"description":"File transfer protocol type. Prefer sftp for security. Use ftps when the\nserver requires TLS. Only use ftp for legacy systems without encryption support."},"hostURI":{"type":"string","description":"FTP server hostname or IP address.\nDo NOT include the protocol prefix (e.g., use \"ftp.example.com\", not \"sftp://ftp.example.com\").\n"},"port":{"type":"number","description":"Server port number. When omitted, defaults to the standard port for the\nprotocol: 21 for ftp, 22 for sftp, 21 for explicit ftps, and 990 for implicit ftps.\n","minimum":0,"maximum":65535},"username":{"type":"string","description":"Username for server authentication."},"password":{"type":"string","writeOnly":true,"description":"Password for server authentication (encrypted at rest; returned masked as `\"******\"`).\nFor sftp, supply either password or authKey (SSH key)."},"authKey":{"type":"string","description":"SSH private key for SFTP key-based authentication (encrypted at rest; returned masked as `\"******\"`).\nOnly used when type is \"sftp\"; can be used alone or alongside a password. Must be an RSA (SSH-2) key\nin PEM format, supplied whole from its BEGIN line to its END line — OpenSSH-format keys (a first\nline that names an OPENSSH PRIVATE KEY), passphrase-protected keys, SSH-1 keys and PuTTY `.ppk` files\nare not supported and must be converted to an unencrypted PEM key first.","writeOnly":true},"usePassiveMode":{"type":"boolean","description":"When true, uses passive mode for FTP/FTPS data connections.\nIn passive mode, the client initiates both control and data connections,\nwhich works better through firewalls and NAT. Enable for most scenarios.\n","default":true},"enableHostVerification":{"type":"boolean","description":"When true, verifies the server's SSH host key (sftp) or TLS certificate (ftps).\nDisable only for development/testing with self-signed certificates.\n"},"userDirectoryIsRoot":{"type":"boolean","description":"When true, treats the user's home directory as the root directory.\nAll paths are relative to the user's home directory rather than the server root.\n","default":false},"useImplicitFtps":{"type":"boolean","description":"When true, uses implicit FTPS (TLS connection established immediately on port 990).\nWhen false, uses explicit FTPS (starts as FTP on port 21, upgrades to TLS via STARTTLS).\nOnly applies when type is \"ftps\".\n","default":false},"requireSocketReUse":{"type":"boolean","description":"When true, requires the data connection to reuse the same TLS session as the control connection.\nSome FTPS servers require this for security. Only applies to FTPS connections.\n","default":false},"entryParser":{"type":"string","enum":["UNIX","UNIX-TRIM","VMS","WINDOWS","OS/2","OS/400","AS/400","MVS","UNKNOWN-TYPE","NETWARE","MACOS-PETER"],"description":"File listing format parser. Controls how directory listings from the server are interpreted.\nMost servers use UNIX format. Only change this if directory listings appear garbled."},"tradingPartner":{"type":"boolean","readOnly":true,"description":"When true, this connection is designated a B2B/EDI trading partner. Read-only on the connection\nbody — POST/PUT of this field are silently ignored; it is toggled via\n`PUT /connections/{_id}/tradingPartner` (used by the EDI B2B Manager).\n"},"_tpConnectorId":{"type":"string","format":"objectId","description":"Reference to the trading partner connector this connection belongs to. Must reference an\nexisting, published trading partner connector; the API rejects an unknown or unpublished ID\nwith 422 `tpconnector_not_found`.\n"},"concurrencyLevel":{"type":"integer","description":"Maximum number of concurrent file transfer operations.\nFTP servers often have low connection limits — keep this value conservative.\nSend no more than the account's licensed maximum, the license's `concurrency` (25 standard,\n50 with an Environments license).\nWhile `autoRecoverRateLimitErrors` is true, which a create gets unless it sends `false`, a create\nignores the value sent here and sets this field to `targetConcurrencyLevel`, or to 1 when no\ntarget is sent. To start higher, send `targetConcurrencyLevel` too, or create with\n`autoRecoverRateLimitErrors: false`.\nUnlike the rest of the `ftp` object, a `PUT` that omits this field keeps the stored value instead of clearing it.\n","minimum":1,"maximum":50,"default":1},"targetConcurrencyLevel":{"type":"integer","description":"While `autoRecoverRateLimitErrors` is true, a create sets `concurrencyLevel` to this value, and a\ncreate that omits it gets 1 for both. Auto-recovery never runs on FTP connections (FTP errors\naren't treated as rate limits), so nothing climbs back to it.\nKept on a `PUT` that omits it, like `concurrencyLevel`; unset by the save while\n`autoRecoverRateLimitErrors` is false.\n","minimum":1,"maximum":50},"multiThreadCount":{"type":"integer","minimum":1,"description":"Number of parallel transfer threads for this FTP connection. Must be a\nwhole number — decimals are rejected on save. Send no more than the\naccount's licensed concurrency maximum, the same as for `concurrencyLevel`. On\nsave the value is mirrored into `userConcurrencyLevel` (and into\n`userTargetConcurrencyLevel` when auto-recovery of rate-limit errors\nis active with `targetConcurrencyLevel` set); clearing it clears the\nmirrors. Not preserved across a `PUT` — re-send it with the rest of\nthe `ftp` object or it is cleared."},"userConcurrencyLevel":{"type":"integer","readOnly":true,"description":"Server-maintained mirror of `multiThreadCount`. Present when\n`multiThreadCount` is set; do not send it — it is recomputed on save."},"userTargetConcurrencyLevel":{"type":"integer","readOnly":true,"description":"Server-maintained mirror of `multiThreadCount`, present while\n`autoRecoverRateLimitErrors` is true and `targetConcurrencyLevel` is\nset; recomputed on save."}},"if":{"properties":{"type":{"const":"sftp"}},"required":["type"]},"then":{"anyOf":[{"required":["password"]},{"required":["authKey"]}]},"else":{"required":["password"]}},"S3":{"type":"object","description":"Configuration for Amazon S3 connections. Used when the connection type is \"s3\". Provides\nupload, download, list, and delete access to S3 buckets. Authenticate with a static IAM\naccess key pair (authType `accesskey`) or by referencing an iClient that holds AWS IAM role\ncredentials (authType `awsIam`). Set pingBucket to an accessible bucket so Celigo can validate\nthe credentials.","properties":{"authType":{"type":"string","enum":["accesskey","awsIam"],"default":"accesskey","description":"Authentication method for the S3 bucket. Defaults to `accesskey` when omitted. Use `awsIam`\nto delegate authentication to an iClient that holds an AWS IAM role instead of embedding a\nstatic key pair."},"accessKeyId":{"type":"string","description":"AWS access key ID for IAM authentication. From an IAM user or role with S3 permissions\n(s3:GetObject, s3:PutObject, s3:ListBucket, etc.). Used when authType is `accesskey`."},"secretAccessKey":{"type":"string","writeOnly":true,"description":"AWS secret access key, paired with accessKeyId. Used when authType is `accesskey`. Encrypted at rest; returned masked as `\"******\"`."},"_iClientId":{"type":"string","format":"objectId","description":"Reference to an iClient that holds AWS IAM role credentials. Required when authType is\n`awsIam`; ignored otherwise. The iClient must carry `awsIam.roleArn`, and that role's name\nmust start with `celigo-file-adaptor-` — the S3 service assumes only roles in that family,\nso a role created for an HTTP or Redshift connection cannot be reused here."},"pingBucket":{"type":"string","description":"S3 bucket name used for connection health checks (ping). The system performs a HEAD request\non this bucket to verify credentials. Must be a bucket the credentials have access to."},"concurrencyLevel":{"type":"integer","description":"Maximum number of concurrent S3 operations. Applies when `autoRecoverRateLimitErrors` is\nfalse; when auto-recover is on (the default) concurrency auto-scales up to\n`targetConcurrencyLevel` and a `concurrencyLevel` sent on its own is reconciled back. Send no\nmore than the account's licensed maximum.","minimum":1,"maximum":50,"default":5},"targetConcurrencyLevel":{"type":"integer","description":"Upper bound for auto-scaled concurrency when `autoRecoverRateLimitErrors` is true (the\ndefault). The system raises and lowers concurrency between 1 and this value based on\nrate-limit feedback from S3.","minimum":1,"maximum":50,"default":5}},"if":{"properties":{"authType":{"const":"awsIam"}},"required":["authType"]},"then":{"required":["_iClientId"]},"else":{"required":["accessKeyId","secretAccessKey"]}},"HTTP":{"type":"object","description":"Configuration for HTTP/REST API connections. Used when the connection type is \"http\".\nThis is the most versatile connection type in Celigo, supporting any REST, SOAP, or generic HTTP API.\nThe auth.type field selects the authentication strategy; each type requires specific sub-fields.","required":["baseURI","mediaType"],"properties":{"mediaType":{"type":"string","enum":["xml","json","urlencoded","form-data","plaintext"],"description":"Default content type for outbound HTTP request bodies.\nControls the Content-Type header and how request bodies are serialized."},"successMediaType":{"type":"string","enum":["xml","csv","json","plaintext"],"description":"Expected content type of successful API responses. Controls how response bodies are parsed.\nIf omitted, the system infers the format from the response Content-Type header."},"errorMediaType":{"type":"string","enum":["xml","json","plaintext"],"description":"Expected content type of error responses from the API. Controls how error response bodies are parsed for extracting error messages.\n\nIf omitted, defaults to the same format as successMediaType.\n"},"baseURI":{"type":"string","description":"Base URL for all API requests made through this connection. Required.\n\nAll relative URIs in exports and imports are appended to this base URL.\nMust be an absolute URL (e.g., \"https://api.example.com/v2\").\nHandlebars expressions are supported for dynamic URLs — e.g.\n\"https://{{{connection.settings.subdomain}}}.example.com\".\n\nDo NOT include trailing slashes — relative URIs in exports/imports should start with \"/\".\n\nUse an HTTPS URL whenever possible. HTTP is not considered a secure protocol; data sent\nto an HTTP endpoint is not encrypted and may be intercepted or modified in transit.\n"},"disableStrictSSL":{"type":"boolean","description":"When true, disables strict SSL/TLS certificate validation for API requests.\n\nOnly set to true for development/testing with self-signed certificates.\nNEVER disable in production — it removes protection against man-in-the-middle attacks.\n","default":false},"concurrencyLevel":{"type":"integer","description":"Maximum number of concurrent HTTP requests this connection can make simultaneously.\n\nHigher values increase throughput but may trigger API rate limits.\nSet this based on the target API's rate limit documentation.\nSend no more than the account's licensed maximum (25 standard, 50 with an Environments license).\nA decimal is rejected with 422 `invalid_field_value` on every write (the same rule applies to every\nadaptor's `concurrencyLevel` and `targetConcurrencyLevel`, and to `ftp.multiThreadCount`).\nPlatform-managed while `autoRecoverRateLimitErrors` is true — a create or PUT ignores the value (a create without `targetConcurrencyLevel` stores 25 where the license's `concurrency` is at least 25) and the recovery machinery moves it toward the target; set `targetConcurrencyLevel` instead.\nAt level 1 an import's pages run one at a time, so a record's existence lookup and write finish before the next record's start (measured on a single import); the import's `idLockTemplate` serializes only same-key records and leaves the rest parallel.\n","minimum":1,"maximum":50,"default":25},"targetConcurrencyLevel":{"type":"integer","description":"Ceiling the platform climbs back to after rate-limit recovery, in steps of 25% of this value.\nWriting it also sets `concurrencyLevel` to the same value and stops any recovery in progress.\n\nHonored only while `autoRecoverRateLimitErrors` is true; ignored, and unset, when it is false.\n","minimum":1,"maximum":50},"retryHeader":{"type":"string","description":"HTTP response header name that contains the retry delay (in seconds) when rate-limited.\n\nDefaults to \"Retry-After\" which is the HTTP standard. Only change this if the API\nuses a non-standard header name for retry-after values.\n","default":"Retry-After"},"formType":{"type":"string","enum":["assistant","rest","http","graph_ql","assistant_graphql"],"description":"Controls the UI form layout for configuring this connection. Determines which\nfields are shown and how they are organized in the Celigo UI.\nFor programmatic creation, http is the most common choice."},"type":{"type":"string","enum":["Amazon-SP-API","Amazon-Hybrid","vendor_central"],"description":"Specific API type for Amazon integrations. Only set this for Amazon connections."},"clientCertificates":{"type":"object","description":"Client certificate configuration for mutual TLS (mTLS) authentication.\n\nUse when the API server requires a client certificate to establish the TLS connection.\nYou can provide either a PEM cert/key pair OR a PFX bundle, but not both.\n","properties":{"cert":{"type":"string","description":"Client certificate in PEM format. Must be paired with the key field.\nCannot be used together with pfx.\n"},"key":{"type":"string","description":"Private key for the client certificate in PEM format (encrypted at rest).","writeOnly":true},"ca":{"type":"string","description":"Certificate Authority (CA) certificate in PEM format.\nUse when the server's certificate is signed by a private CA not in the default trust store.\n"},"passphrase":{"type":"string","description":"Passphrase to decrypt an encrypted private key or PFX bundle (encrypted at rest).","writeOnly":true},"pfx":{"type":"string","description":"PKCS#12 (.pfx/.p12) bundle containing both the certificate and private key (encrypted at rest).\nCannot be used together with cert/key.\n","writeOnly":true}}},"ping":{"type":"object","description":"Connection health check (ping) configuration. Defines how Celigo tests\nwhether this connection is alive and authenticated.\n\nWhen configured, Celigo sends an HTTP request to the specified endpoint and\nevaluates the response to determine connection health. The ping runs when\ntesting the connection in the UI and periodically during flow execution.\n","properties":{"relativeURI":{"type":["string","null"],"description":"Relative URI appended to baseURI for the ping request.\nShould be a lightweight, fast endpoint (e.g., \"/me\", \"/health\", \"/api/v1/status\").\nMay be null when no ping endpoint is configured.\n"},"method":{"type":"string","enum":["GET","POST","PUT","HEAD"],"description":"HTTP method for the ping request. Defaults to GET.\nUse POST only if the health endpoint requires it.\n","default":"GET"},"body":{"type":"string","description":"Request body for the ping request. Only used when method is POST or PUT.\nFor form-data mediaType, must be valid multipart form data.\n"},"successPath":{"type":"string","description":"JSON path or XPath expression to extract a success indicator from the ping response.\nIf the value at this path matches one of the successValues, the ping succeeds.\nIf omitted, any 2xx response is considered successful.\n"},"successValues":{"type":"array","items":{"type":"string"},"description":"Values that indicate a successful ping when found at successPath.\nRequires successPath to be set.\n"},"allowArrayforSuccessPath":{"type":"boolean","description":"When true, the value at successPath can be an array and any matching element counts as success."},"failPath":{"type":"string","description":"JSON path or XPath expression to extract a failure indicator from the ping response.\nIf the value at this path matches one of the failValues, the ping fails even if the HTTP status is 2xx.\n"},"failValues":{"type":"array","items":{"type":"string"},"description":"Values that indicate a failed ping when found at failPath.\nRequires failPath to be set.\n"},"errorPath":{"type":"string","description":"JSON path or XPath expression to extract a human-readable error message from\na failed ping response. The extracted message is shown to the user in the UI.\n"}}},"auth":{"type":"object","description":"Authentication configuration for the API connection.\n\nThe auth.type field selects the authentication strategy. Each type requires\nspecific sub-fields — see the type field description for details.\n","properties":{"type":{"type":"string","enum":["custom","basic","token","oauth","wsse","cookie","digest","oauth1","jwtbearer","awsiam"],"description":"Authentication method for this connection. Determines which auth sub-fields are required.\nEach type has its own credential fields; see the x-enumDescriptions for details."},"failStatusCode":{"type":"number","description":"HTTP status code that indicates an authentication failure (e.g., 401, 403).\nWhen this status code is received, the system triggers re-authentication\nbefore retrying the request.\n"},"failPath":{"type":"string","description":"JSON path or XPath expression to check in response bodies for authentication failure indicators.\nUsed when APIs return 200 OK but embed auth errors in the response body.\n"},"failValues":{"type":"array","items":{"type":"string"},"description":"Values at failPath that indicate an authentication failure.\nRequires failPath to be set.\n"},"failures":{"type":"array","description":"HTTP status codes that indicate an authentication failure and should trigger\nre-authentication. An alternative to failStatusCode that accepts multiple codes.\n","items":{"type":"object","properties":{"statusCode":{"type":"number","description":"HTTP status code that signals an authentication failure (e.g., 403)."}}}},"skipFollowAuthorizationHeader":{"type":"boolean","description":"When true, the Authorization header is NOT forwarded on HTTP redirects.\nEnable this for APIs that redirect to a different domain after authentication.\n"},"basic":{"type":"object","description":"Basic authentication credentials. Required when auth.type is \"basic\", \"wsse\", or \"digest\".\n","properties":{"username":{"type":"string","description":"Username for Basic/Digest/WSSE authentication."},"password":{"type":"string","description":"Password for Basic/Digest/WSSE authentication (encrypted at rest). On update, the\nmasked `\"******\"` sent back keeps the stored password; a new value replaces it.","writeOnly":true}}},"token":{"type":"object","description":"Token-based authentication configuration. Required when auth.type is \"token\".\n\nSupports static API keys/bearer tokens and automatic token refresh flows.\nThe token can be sent in a header (Authorization), query parameter, or request body.\n","properties":{"token":{"type":"string","description":"The API key or bearer token value (encrypted at rest); returned masked as `\"******\"`.\nOn update, the mask sent back keeps the stored token; a new value replaces it.\nRequired unless automatic token refresh is configured: a token block without a\ntoken must carry a `refreshMethod`, so a create or update that sends neither fails\nwith 422 `Expected field: refreshMethod to be present.` To create a static-token\nconnection before the real token is available, send a placeholder value and\nreplace it later.\n"},"location":{"type":"string","enum":["url","header","body"],"description":"Where to include the token in outbound requests.\nMost APIs expect header. Use headerName and scheme to control the header format,\nor paramName when sending as a URL query parameter."},"headerName":{"type":"string","description":"HTTP header name for the token when location is \"header\".\nDefaults to \"Authorization\" if omitted.\n"},"scheme":{"type":"string","description":"Token scheme/prefix when sent in a header. Prepended before the token value.\nCommon values: \"Bearer\", \"Token\", \"Basic\".\nExample: scheme \"Bearer\" produces header \"Authorization: Bearer <token>\".\n"},"paramName":{"type":"string","description":"Query parameter name for the token when location is \"url\".\nExample: paramName \"api_key\" produces URL \"?api_key=<token>\".\n"},"refreshMethod":{"type":"string","enum":["GET","POST","PUT"],"description":"HTTP method for automatic token refresh requests.\nRequired when no static token is provided (refresh-based auth flow).\n","default":"POST"},"refreshRelativeURI":{"type":"string","description":"Relative URI (appended to baseURI) for the token refresh endpoint.\nThe system calls this endpoint to obtain a new token when the current one expires.\n"},"refreshBody":{"type":"string","description":"Request body to send with the token refresh request."},"refreshMediaType":{"type":"string","enum":["json","urlencoded","xml","plaintext"],"description":"Content type for the token refresh request body.\n","default":"urlencoded"},"refreshResponseMediaType":{"type":"string","enum":["json","xml"],"description":"Expected content type of the token refresh response."},"refreshTokenPath":{"type":"string","description":"JSON path to extract the new token from the refresh response.\nExample: \"access_token\" or \"data.token\".\n"},"refreshToken":{"type":"string","description":"Refresh token used to obtain a new access token (encrypted at rest).","writeOnly":true},"refreshTokenLocation":{"type":"string","enum":["header","body"],"description":"Where to include the refresh token in refresh requests."},"refreshHeaders":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"Header name to send with the token-refresh request."},"value":{"type":"string","description":"Header value to send with the token-refresh request."}}},"description":"Additional headers to include in token refresh requests."},"tokenPaths":{"type":"array","items":{"type":"string"},"description":"JSON paths to extract multiple token values from the refresh response.\nUse when the refresh response contains tokens at different paths that need\nto be stored for subsequent requests.\n"},"revoke":{"type":"object","description":"Token-revocation request configuration. When set, the system calls this\nendpoint to revoke the current token (e.g. when the connection is deleted or\nre-authenticated). Used mainly by pre-built HTTP Connector templates.\n","properties":{"uri":{"type":"string","description":"Absolute URL of the token-revocation endpoint."},"body":{"type":"string","description":"Request body to send with the token-revocation request."},"headers":{"type":"array","description":"Additional headers to include in the token-revocation request.","items":{"type":"object","properties":{"name":{"type":"string","description":"Header name to send with the revocation request."},"value":{"type":"string","description":"Header value to send with the revocation request."}}}}}}}},"oauth":{"$ref":"#/components/schemas/OAuth"},"cookie":{"type":"object","description":"Cookie-based session authentication. Required when auth.type is \"cookie\".\n\nThe system authenticates by sending a request to the login URI, captures the\nsession cookies from the response, and includes them in all subsequent API requests.\n","properties":{"uri":{"type":"string","description":"Login endpoint URI for cookie authentication. Required.\nThe system sends a request to this URI to obtain session cookies.\n\nUse an HTTPS URL whenever possible. HTTP is not considered a secure protocol;\ndata sent to an HTTP endpoint is not encrypted and may be intercepted or\nmodified in transit.\n"},"body":{"type":"string","description":"Request body for the login request (e.g., JSON with username/password)."},"method":{"type":"string","description":"HTTP method for the login request (typically POST)."},"successStatusCode":{"type":"number","description":"HTTP status code that confirms successful authentication.\nIf the login response returns this status code, the session cookies are captured.\n"}}},"jwt":{"$ref":"#/components/schemas/JWT"}},"if":{"properties":{"type":{"enum":["basic","digest","wsse"]}},"required":["type"]},"then":{"required":["basic"],"properties":{"basic":{"required":["username","password"]}}},"else":{"if":{"properties":{"type":{"const":"token"}},"required":["type"]},"then":{"required":["token"],"properties":{"token":{"required":["token","location"]}}},"else":{"if":{"properties":{"type":{"const":"cookie"}},"required":["type"]},"then":{"required":["cookie"],"properties":{"cookie":{"required":["uri"]}}},"else":{"if":{"properties":{"type":{"const":"jwtbearer"}},"required":["type"]},"then":{"required":["jwt"],"properties":{"jwt":{"required":["signatureMethod","payload"]}},"if":{"properties":{"jwt":{"properties":{"signatureMethod":{"enum":["hmac-sha256","hmac-sha384","hmac-sha512"]}},"required":["signatureMethod"]}},"required":["jwt"]},"then":{"properties":{"jwt":{"required":["signatureMethod","payload","secret"]}}},"else":{"properties":{"jwt":{"required":["signatureMethod","payload","privateKey"]}}}},"else":{"if":{"properties":{"type":{"const":"oauth1"}},"required":["type"]},"then":{"required":["oauth"],"properties":{"oauth":{"required":["oauth1"],"properties":{"oauth1":{"required":["signatureMethod","consumerKey","accessToken"]}}}},"if":{"properties":{"oauth":{"properties":{"oauth1":{"properties":{"signatureMethod":{"enum":["rsa-sha1","rsa-sha256","rsa-sha512"]}},"required":["signatureMethod"]}},"required":["oauth1"]}},"required":["oauth"]},"then":{"properties":{"oauth":{"properties":{"oauth1":{"required":["signatureMethod","consumerKey","accessToken","consumerPrivateKey"]}}}}},"else":{"properties":{"oauth":{"properties":{"oauth1":{"required":["signatureMethod","consumerKey","accessToken","consumerSecret","tokenSecret"]}}}}}}}}}}},"rateLimit":{"type":"object","description":"Rate limiting configuration. Defines how the system detects and handles\nAPI rate limit responses.\n\nWhen rate limiting is detected, the system pauses requests and waits for\nthe retry-after period before resuming. The retryHeader field on the parent\nHTTP object controls which response header contains the wait time.\n","properties":{"failStatusCode":{"type":"number","description":"HTTP status code that indicates the API is rate-limiting requests.\nDefaults to 429 (Too Many Requests) which is the HTTP standard.\nChange only if the API uses a non-standard status code for rate limits.\n","default":429},"failPath":{"type":"string","description":"JSON path or XPath to check in response bodies for rate limit indicators.\nUsed when APIs return 200 OK but embed rate limit errors in the response body.\n"},"failValues":{"type":"array","items":{"type":"string"},"description":"Values at failPath that indicate rate limiting. Requires failPath to be set.\n"},"limit":{"type":"number","minimum":1,"description":"Maximum number of requests per rate-limit window. When set, the connection's\neffective concurrency level must be 1 to ensure proper rate limit enforcement.\n"}}},"headers":{"type":"array","description":"Default HTTP headers included in every request made through this connection.\nUse for API keys in custom headers, content negotiation, or any headers the API requires on all requests.\n","items":{"type":"object","properties":{"name":{"type":"string","description":"Header name (e.g., \"X-API-Key\", \"Accept\")."},"value":{"type":"string","description":"Header value. Supports handlebars expressions for dynamic values."}},"required":["name","value"]}},"encrypted":{"type":["object","string"],"description":"Encrypted custom fields for storing sensitive configuration values (API secrets,\nprivate keys, etc.) that don't fit standard auth fields. Sent as an object of\nfield-name/value pairs; values are encrypted at rest. Returned as the masked\nstring `\"******\"` on responses; on update, that mask sent back keeps the stored values,\nand a new object replaces them. Field definitions are specified in encryptedFields.\n"},"encryptedFields":{"type":"array","description":"Metadata defining the encrypted custom fields available on this connection.\nEach entry describes a field in the encrypted object — its ID, label, and UI position.\n","items":{"type":"object","properties":{"id":{"type":"string","description":"Field identifier — matches the key in the encrypted object."},"label":{"type":"string","description":"Human-readable label shown in the UI."},"required":{"type":"boolean","default":false,"description":"When true, the custom field defined by this entry is mandatory — a value for it must be supplied before the connection can be saved."},"position":{"type":"number","description":"Display order in the UI form."},"helpText":{"type":"string","description":"Tooltip or help text shown next to the field in the UI."}}}},"unencrypted":{"type":"object","description":"Unencrypted custom fields for non-sensitive configuration values.\nField definitions are specified in unencryptedFields.","properties":{"marketplaceId":{"type":"string","description":"Amazon marketplace identifier for Amazon connection types."},"sellingRegion":{"type":"string","description":"Amazon selling region for the marketplace."},"googleProjectId":{"type":"string","description":"Google Cloud project id for Google Cloud Storage connections\n(assistant `googlecloudstorage`, or a `baseURI` pointing at\n`storage.googleapis.com`)."}}},"unencryptedFields":{"type":"array","description":"Metadata defining the unencrypted custom fields available on this connection.\nEach entry describes a field in the unencrypted object.\n","items":{"type":"object","properties":{"id":{"type":"string","description":"Field identifier — matches the key in the unencrypted object."},"label":{"type":"string","description":"Human-readable label shown in the UI."},"required":{"type":"boolean","default":false,"description":"When true, the custom field defined by this entry is mandatory — a value for it must be supplied before the connection can be saved."},"position":{"type":"number","description":"Display order in the UI form."},"helpText":{"type":"string","description":"Tooltip or help text shown next to the field in the UI."},"type":{"type":"string","description":"Field type hint for the UI (e.g., \"text\", \"select\")."}}}},"_iClientId":{"type":"string","format":"objectId","description":"iClient that holds the credentials this connection signs with: the OAuth 2.0 client for\n`auth.type` `oauth` (including the `azureserviceprincipal` service principal an Azure\nData Lake Storage Gen2 connection authenticates with and the `googleserviceaccount` key\na Google Cloud Storage connection uses), or the `awsIam` role for `auth.type` `awsiam`.\nMust belong to the same account as the connection. Omit for every other auth type."},"_httpConnectorId":{"type":"string","format":"objectId","description":"HTTP connector (pre-built application template) this connection is linked to. Linking\nlets exports and imports on the connection pick endpoints from the connector's catalog and\ndrives the `assistant` form in the UI. The link is resolved server-side on create and on\nany update that changes `assistant` or a connector id, and the result overwrites\n`_httpConnectorId`, `_httpConnectorApiId` and `_httpConnectorVersionId`: an id that does\nnot resolve to an accessible connector is dropped rather than rejected, and when the\ntop-level `assistant` names an application with a legacy adaptor (the connector's\n`legacyId`, e.g. `shopify`) the connector resolved from that slug replaces the id you sent\nand a sent `_httpConnectorVersionId` is dropped. Read the response back to confirm the\nlink took."},"_httpConnectorApiId":{"type":"string","format":"objectId","description":"API within the linked HTTP connector that this connection targets, for connectors that\npublish more than one API. Only meaningful together with `_httpConnectorId`; an id that is\nnot one of that connector's APIs is dropped on save, not rejected."},"_httpConnectorVersionId":{"type":"string","format":"objectId","description":"Version entry of the linked HTTP connector (an item of the connector's `versions` array)\nwhose endpoint definitions this connection uses. Only meaningful together with\n`_httpConnectorId`; an id that is not one of that connector's published versions is\nreplaced by a published version of the connector on create and dropped on update, never\nrejected."},"isRest":{"type":"boolean","description":"When true, this HTTP connection uses REST-style semantics (created from a REST connector template)."},"useNewAuthFailSchema":{"type":"boolean","description":"When true, the connection uses the newer authentication-failure detection schema for refresh/retry handling."}},"if":{"properties":{"type":{"enum":["Amazon-SP-API","Amazon-Hybrid","vendor_central"]}},"required":["type"]},"then":{"required":["unencrypted"],"properties":{"unencrypted":{"required":["marketplaceId","sellingRegion"]}}},"else":{"if":{"properties":{"auth":{"properties":{"type":{"const":"awsiam"}},"required":["type"]}},"required":["auth"]},"then":{"required":["_iClientId"]}}},"OAuth":{"type":"object","description":"OAuth 2.0 and OAuth 1.0a authentication configuration.\nUsed as a sub-object within HTTP and REST connection auth configurations.\nThe grantType field selects the OAuth 2.0 flow; for legacy OAuth 1.0a APIs, use the oauth1 sub-object.","properties":{"type":{"type":"string","enum":["custom","assistant"],"description":"OAuth configuration mode. Controls whether settings are user-configured or\npre-populated by an application assistant connector."},"grantType":{"type":"string","enum":["authorizecode","clientcredentials","password"],"description":"OAuth 2.0 grant type that determines the authentication flow.\nUse authorizecode for user-context integrations, clientcredentials for\nserver-to-server, and password only when the API does not support other flows.","default":"authorizecode"},"authURI":{"type":"string","description":"OAuth 2.0 authorization endpoint URL.\nRequired for \"authorizecode\" grant type. The user is redirected to this URL\nto authorize the application.\nHandlebars expressions are supported for tenant-specific endpoints — e.g.\n\"https://{{{connection.settings.storeName}}}.myshopify.com/admin/oauth/authorize\".\n\nUse an HTTPS URL whenever possible. HTTP is not considered a secure protocol; data sent\nto an HTTP endpoint is not encrypted and may be intercepted or modified in transit.\n"},"tokenURI":{"type":"string","description":"OAuth 2.0 token endpoint URL.\nRequired for \"authorizecode\", \"clientcredentials\", and \"password\" grant types.\nThe system exchanges credentials or authorization codes for access tokens at this URL.\nHandlebars expressions are supported for tenant-specific endpoints.\n\nUse an HTTPS URL whenever possible. HTTP is not considered a secure protocol; data sent\nto an HTTP endpoint is not encrypted and may be intercepted or modified in transit.\n"},"skipOauthValidations":{"type":"boolean","description":"When true, skips Celigo's built-in OAuth configuration validation.\nUse when the API has non-standard OAuth requirements that conflict with validation rules.\n","default":false},"scope":{"type":"array","items":{"type":"string"},"description":"OAuth scopes to request during authorization. Controls the level of API access.\nScope values are API-specific (e.g., \"read\", \"write\", \"admin\").\n"},"scopeDelimiter":{"type":"string","description":"Delimiter between multiple scope values. Defaults to a space (\" \") per the\nOAuth 2.0 spec. Some APIs use commas or other delimiters.\n","default":" "},"clientId":{"type":"string","description":"OAuth client ID (application ID) registered with the API provider. An `http`\nconnection takes the app from a `custom_oauth2` iClient referenced by `http._iClientId`\n(an `mcp` connection from `mcp.http._iClientId`) and doesn't store this field: a create\nthat sends `clientId` and `clientSecret` here answers 201 without either (and stores\n`useIClientFields: true` unless `false` is sent).\n"},"clientSecret":{"type":"string","description":"OAuth client secret (encrypted at rest). Not stored on an `http` connection: the secret\nbelongs on the iClient (see `clientId`).\n","writeOnly":true},"username":{"type":"string","description":"Resource owner username. Required when grantType is \"password\".\n"},"password":{"type":"string","description":"Resource owner password (encrypted at rest). Required when grantType is \"password\".\n","writeOnly":true},"clientCredentialsLocation":{"type":"string","enum":["basicauthheader","body"],"description":"Where to send client credentials in token requests. Defaults to basicauthheader\n(HTTP Basic Auth), which is recommended by the OAuth spec. Use body when\nthe API does not support Basic Auth for client credentials.","default":"basicauthheader"},"accessTokenPath":{"type":"string","description":"JSON path to extract the access token from the token endpoint response.\nDefaults to \"access_token\" per the OAuth 2.0 spec.\nChange only if the API returns the token at a non-standard path.\n"},"accessTokenHeaders":{"type":"array","description":"Additional HTTP headers to include in token endpoint requests.\nUse for APIs that require custom headers beyond the standard OAuth parameters.\n","items":{"type":"object","properties":{"name":{"type":"string","description":"Header name to send with the token request."},"value":{"type":"string","description":"Header value to send with the token request."}}}},"accessTokenBody":{"type":"string","description":"Additional body content to include in token endpoint requests.\nAppended to the standard OAuth parameters.\n"},"oauth2RedirectUrl":{"type":"string","description":"OAuth 2.0 redirect URI (callback URL) registered with the API provider.\nMust exactly match the redirect URI configured in the OAuth application registration.\n"},"useIClientFields":{"type":"boolean","description":"When true, uses iClient-managed OAuth credentials (clientId/clientSecret)\ninstead of the values in this configuration. The iClient is the connection's\n`_iClientId` — on an HTTP connection `http._iClientId`, beside `auth`, not inside it —\nand it also supplies the grant type and the authorization and token endpoints, so a\ncreate needs only `auth.type: \"oauth\"`, `auth.oauth.useIClientFields: true` and the\niClient id. The connection holds no tokens until a person completes the authorization\nin a browser.\n"},"oauth1":{"type":"object","description":"OAuth 1.0a configuration for legacy APIs that use the older OAuth protocol.\nAlways needs consumerKey and accessToken; HMAC signature methods also need\nconsumerSecret and tokenSecret, while RSA methods need consumerPrivateKey.","properties":{"consumerKey":{"type":"string","description":"OAuth 1.0a consumer key (API key).\nIdentifies the application making the request.\n"},"consumerSecret":{"type":"string","description":"OAuth 1.0a consumer secret (encrypted at rest).\nRequired for HMAC and PLAINTEXT signature methods.\n","writeOnly":true},"accessToken":{"type":"string","description":"OAuth 1.0a access token (encrypted at rest).\nRepresents the user's authorization for the application to access their data.\n","writeOnly":true},"tokenSecret":{"type":"string","description":"OAuth 1.0a token secret (encrypted at rest).\nRequired for HMAC and PLAINTEXT signature methods.\n","writeOnly":true},"signatureMethod":{"type":"string","enum":["hmac-sha1","hmac-sha256","hmac-sha512","rsa-sha1","rsa-sha256","rsa-sha512","plaintext"],"description":"OAuth 1.0a request signing method. HMAC methods require consumerSecret and\ntokenSecret; RSA methods require consumerPrivateKey. PLAINTEXT offers no\ncryptographic signing and should only be used for testing over HTTPS."},"consumerPrivateKey":{"type":"string","description":"RSA private key for OAuth 1.0a RSA signature methods (encrypted at rest).\nRequired when signatureMethod is RSA-SHA1, RSA-SHA256, or RSA-SHA512.\n","writeOnly":true},"realm":{"type":"string","description":"OAuth realm value included in the Authorization header.\nSome APIs require this to identify the authentication domain.\n"}}},"pkceCodeVerifier":{"type":"string","description":"PKCE (Proof Key for Code Exchange) code verifier for enhanced OAuth 2.0 security.\nManaged internally by the system during authorization code flows.\n","writeOnly":true}},"if":{"properties":{"grantType":{"const":"authorizecode"}},"required":["grantType"]},"then":{"required":["authURI","tokenURI"]},"else":{"if":{"properties":{"grantType":{"const":"clientcredentials"}},"required":["grantType"]},"then":{"required":["tokenURI"]},"else":{"if":{"properties":{"grantType":{"const":"password"}},"required":["grantType"]},"then":{"required":["tokenURI","username","password"]}}}},"JWT":{"type":"object","description":"JWT Bearer authentication configuration. Used when auth.type is \"jwtbearer\" on HTTP\nconnections. The connection builds a JWT from payload and headers, signs it using\nsignatureMethod, and sends it as the bearer token. HMAC methods sign with secret;\nRSA/ECDSA/PSS methods sign with privateKey.","properties":{"signatureMethod":{"type":"string","enum":["hmac-sha256","hmac-sha384","hmac-sha512","rsa-sha256","rsa-sha384","rsa-sha512","es256","es384","es512","ps256","ps384","ps512"],"description":"JWT signing method. Required when auth.type is \"jwtbearer\". HMAC methods require\nthe secret field; RSA/ECDSA/PSS methods require the privateKey field."},"payload":{"type":"object","additionalProperties":true,"description":"JWT claims payload (the token body). Required and must be non-empty when auth.type\nis \"jwtbearer\". Keys are JWT claim names (e.g. iss, sub, aud, exp)."},"headers":{"type":"object","additionalProperties":true,"description":"JWT header parameters merged into the generated token header (e.g. kid)."},"secret":{"type":"string","writeOnly":true,"description":"Shared secret for HMAC signature methods (hmac-sha256/hmac-sha512), encrypted at rest.\nRequired when signatureMethod is an HMAC method."},"isSecretBase64Encoded":{"type":"boolean","description":"When true, the secret is base64-decoded before being used to sign."},"privateKey":{"type":"string","writeOnly":true,"description":"PEM-encoded private key for RSA/ECDSA/PSS signature methods, encrypted at rest.\nRequired for any rsa-*, es*, or ps* signature method."},"token":{"type":"string","writeOnly":true,"description":"Pre-generated static JWT to use instead of building one from payload (encrypted at rest).\nUse only when the API issues a long-lived JWT that does not need regeneration."}},"if":{"properties":{"signatureMethod":{"enum":["hmac-sha256","hmac-sha384","hmac-sha512"]}},"required":["signatureMethod"]},"then":{"required":["secret"]},"else":{"if":{"properties":{"signatureMethod":{"enum":["rsa-sha256","rsa-sha384","rsa-sha512","es256","es384","es512","ps256","ps384","ps512"]}},"required":["signatureMethod"]},"then":{"required":["privateKey"]}}},"RDBMS":{"type":"object","description":"Configuration for relational database connections. Used when the connection type is \"rdbms\".\nThe type field selects the database system, which determines the SQL dialect, connection driver,\ndefault port, and which additional sub-fields are required.","required":["type"],"properties":{"type":{"type":"string","enum":["mysql","postgresql","mssql","snowflake","oracle","bigquery","redshift","mariadb","azuresynapse"],"description":"The specific relational database system to connect to. Determines the SQL dialect,\nconnection driver, default port, and which additional sub-fields are required."},"host":{"type":"string","description":"Database server hostname or IP address.\nRequired for all types except BigQuery (which uses Google's API endpoints) and Redshift\n(which is reached through its cluster identifier and region instead of a host).\n\nFor Snowflake, use the account URL format: \"account_identifier.snowflakecomputing.com\".\n"},"port":{"type":"number","description":"Database server port number. If omitted, uses the default port for the database type:\n- MySQL/MariaDB: 3306\n- PostgreSQL: 5432\n- MS SQL/Azure Synapse: 1433\n- Oracle: 1521\n- Snowflake: 443\n- Redshift: 5439\n","minimum":1,"maximum":65535},"database":{"type":"string","description":"Database name to connect to. Required for most types.\n\nFor Oracle, use the serviceName field instead of database.\nFor BigQuery, use bigquery.dataset to specify the target dataset.\n"},"instanceName":{"type":"string","description":"Named instance identifier, used when the server hosts multiple named database instances\n(primarily MS SQL Server). Leave empty for a default instance.\n"},"user":{"type":"string","description":"Database username for authentication. Required for all types except\nBigQuery (service account auth), Redshift, and `mssql` / `azuresynapse`\nwith `mssql.authType=azure-service-principal`, where the Entra principal\nin the iClient signs in and a `user` sent anyway is stored unused.\n"},"password":{"type":"string","description":"Database password (encrypted at rest). Required alongside user for password-based auth.","writeOnly":true},"version":{"type":"string","enum":["SQL Server 2008 R2","SQL Server 2012","SQL Server 2014","SQL Server 2016","SQL Server 2017","Azure"],"description":"SQL Server engine version, which selects driver compatibility behavior. Applies to mssql\nand azuresynapse connections only (azuresynapse is always \"Azure\")."},"serviceName":{"type":"string","description":"Oracle service name, supplied instead of the database field for Oracle connections.\nThis is the TNS service name or pluggable database (PDB) service name.\n"},"serverType":{"type":"string","enum":["dedicated","shared","pooled"],"description":"Oracle server connection type. Controls the server process model used for connections."},"concurrencyLevel":{"type":"integer","description":"Maximum number of concurrent database connections.\nSet based on the database server's connection limit and available resources.\nSend no more than the account's licensed maximum (25 standard, 50 with an Environments license).\n","minimum":1,"maximum":50,"default":5},"targetConcurrencyLevel":{"type":"integer","description":"Target concurrency level for auto-scaling. The system adjusts the number of\nconcurrent connections between 1 and this value based on performance feedback.\n","minimum":1,"maximum":50},"disableStrictSSL":{"type":"boolean","description":"When true, disables strict SSL/TLS certificate validation for the database connection.\nOnly use for development/testing with self-signed certificates.\n","default":false},"snowflake":{"type":"object","description":"Snowflake-specific configuration. Required when type is \"snowflake\".\n","required":["authType"],"properties":{"warehouse":{"type":"string","description":"Snowflake virtual warehouse that provides compute resources for queries.\nMust be a warehouse the user's role can access."},"schema":{"type":"string","description":"Default Snowflake schema. If omitted, queries must fully-qualify table names\n(e.g., DATABASE.SCHEMA.TABLE).\n"},"role":{"type":"string","description":"Snowflake security role to use for the session. Determines which databases,\nschemas, and warehouses are accessible. Defaults to the user's default role.\n"},"authType":{"type":"string","enum":["keyPair"],"description":"Authentication type for Snowflake. keyPair uses RSA key-pair authentication and requires\nthe connection's key field. It is the only type the connection form offers for new\nconnections (password-based auth is no longer available)."}}},"mssql":{"type":"object","description":"Microsoft SQL Server / Azure Synapse-specific configuration. Read for\nboth the `mssql` and the `azuresynapse` types — Azure Synapse\nAnalytics shares SQL Server's authentication model and this\nsub-object.","properties":{"authType":{"type":"string","enum":["basic","azure-service-principal"],"description":"How a Microsoft SQL Server or Azure Synapse connection\nauthenticates. Defaults to `basic` when omitted (the connection\nform's \"Database user\"). With `azure-service-principal` the\nconnection signs in as the Entra application registered in the\niClient — a client secret, or on SQL Server a certificate — and\n`_iClientId` must reference it. The SQL Server connection form\noffers `azure-service-principal` in Cloud mode only and saves\n`basic` for an on-premise connection (`_agentId` set).","default":"basic"}}},"bigquery":{"type":"object","description":"Google BigQuery-specific configuration. Required when type is \"bigquery\".\nUses Google Cloud service account credentials for authentication.\n","properties":{"projectId":{"type":"string","description":"Google Cloud project ID that contains the BigQuery datasets.\nFound in the Google Cloud Console project settings.\n"},"dataset":{"type":"string","description":"Default BigQuery dataset name.\nQueries will target tables within this dataset unless fully-qualified names are used.\n"},"clientEmail":{"type":"string","format":"email","description":"Google Cloud service account email address.\nThe service account must have BigQuery Data Editor and BigQuery Job User roles.\n"},"privateKey":{"type":"string","description":"Google Cloud service account private key in PEM format (encrypted at rest).\nDownloaded as part of the service account JSON key file.\n","writeOnly":true}}},"redshift":{"type":"object","description":"Amazon Redshift-specific configuration. `region` is always required.\nCredentials depend on `authType`: static access keys in `aws` for\n`accesskey` (the default), or an `awsIam` iClient referenced by\n`rdbms._iClientId` for `awsIam`. The top-level user and password are optional.\n","properties":{"authType":{"type":"string","enum":["accesskey","awsIam"],"default":"accesskey","description":"Selects the Redshift authentication mode; omitting it behaves as\n`accesskey`. With `awsIam`, the platform assumes the iClient's\nrole and requires exactly one of `clusterIdentifier` (provisioned\ncluster) or `workgroupName` (Redshift Serverless) — supplying\nboth or neither fails with 422. A bulk-load import saves against\neither mode, cluster or Serverless workgroup alike."},"aws":{"type":"object","description":"Static AWS access keys, used when `authType` is `accesskey` (or\nomitted). Not used with `awsIam` — credentials then come from the\niClient.","properties":{"accessKeyId":{"type":"string","description":"AWS access key ID for IAM authentication."},"secretAccessKey":{"type":"string","description":"AWS secret access key (encrypted at rest).","writeOnly":true}}},"clusterIdentifier":{"type":"string","description":"Redshift cluster identifier, used with the region to reach a\nprovisioned cluster. With `awsIam` auth, exactly one of\n`clusterIdentifier` or `workgroupName` must be set."},"workgroupName":{"type":"string","description":"Redshift Serverless workgroup to connect to instead of a\nprovisioned cluster. Only valid when `authType` is `awsIam` —\nthe API rejects it with `accesskey` auth (422 \"Redshift\nServerless (workgroupName) requires authType=awsIam\") — and is\nmutually exclusive with `clusterIdentifier`."},"region":{"type":"string","description":"AWS region where the Redshift cluster is deployed.\n","enum":["us-east-1","us-east-2","us-west-1","us-west-2","eu-west-1","eu-west-2","eu-west-3","eu-north-1","eu-central-1","ap-southeast-1","ap-southeast-2","ap-northeast-1","ap-northeast-2","ap-south-1","sa-east-1","ca-central-1"]}}},"ssl":{"$ref":"#/components/schemas/SSL"},"options":{"type":"array","description":"Additional database driver connection options as name/value pairs.\nUse for driver-specific settings not covered by the standard fields\n(e.g., connection timeout, charset, application name).\n","items":{"type":"object","properties":{"name":{"type":"string","description":"Option name (driver-specific)."},"value":{"type":"string","description":"Option value."}},"required":["name","value"]}},"key":{"type":"string","writeOnly":true,"description":"RSA private key (PEM-encoded, encrypted at rest). Required when type is `snowflake`\nand `snowflake.authType` is `keyPair`. Not used by any other database type."},"passphrase":{"type":"string","writeOnly":true,"description":"Passphrase that decrypts the RSA private key in the key field, when that key is\nencrypted (encrypted at rest). Used only for `snowflake` with `snowflake.authType`\n`keyPair`; omit when the private key is unencrypted."},"_iClientId":{"type":"string","format":"objectId","description":"Reference to an iClient holding auth credentials, stored inside the\nrdbms object. Required when type is `mssql` or `azuresynapse` and\n`mssql.authType` is `azure-service-principal` (an\n`azureserviceprincipal` iClient — the Microsoft Entra tenant id,\nclient id and client secret or certificate), and when type is\n`redshift` and `redshift.authType` is `awsIam` (an `awsIam`-provider\niClient holding the role ARN to assume). On `mssql` / `azuresynapse`\nit is rejected when `mssql.authType` is `basic` or omitted. For\nRedshift the iClient must carry `awsIam.roleArn`, and that role's name\nmust start with `celigo-data-warehouse-adaptor-` — the data-warehouse\nservice assumes only roles in that family, so a role created for an S3\nor HTTP connection cannot be reused here."}},"if":{"properties":{"type":{"enum":["mysql","postgresql","mariadb"]}},"required":["type"]},"then":{"required":["host","database","user","password"]},"else":{"if":{"properties":{"type":{"const":"mssql"}},"required":["type"]},"then":{"if":{"properties":{"mssql":{"properties":{"authType":{"const":"azure-service-principal"}},"required":["authType"]}},"required":["mssql"]},"then":{"required":["host","database","version","_iClientId"]},"else":{"required":["host","database","version","user","password"]}},"else":{"if":{"properties":{"type":{"const":"azuresynapse"}},"required":["type"]},"then":{"if":{"properties":{"mssql":{"properties":{"authType":{"const":"azure-service-principal"}},"required":["authType"]}},"required":["mssql"]},"then":{"required":["host","database","_iClientId"]},"else":{"required":["host","database","user","password"]}},"else":{"if":{"properties":{"type":{"const":"snowflake"}},"required":["type"]},"then":{"required":["host","database","user"],"properties":{"snowflake":{"required":["authType","warehouse"]}},"if":{"properties":{"snowflake":{"properties":{"authType":{"const":"keyPair"}},"required":["authType"]}},"required":["snowflake"]},"then":{"required":["key"]},"else":{"required":["password"]}},"else":{"if":{"properties":{"type":{"const":"oracle"}},"required":["type"]},"then":{"required":["host","user","password"]},"else":{"if":{"properties":{"type":{"const":"bigquery"}},"required":["type"]},"then":{"required":["bigquery"],"properties":{"bigquery":{"required":["projectId","dataset","clientEmail","privateKey"]}}},"else":{"if":{"properties":{"type":{"const":"redshift"}},"required":["type"]},"then":{"required":["database","user","redshift"],"properties":{"redshift":{"required":["region"]}},"if":{"required":["redshift"],"properties":{"redshift":{"required":["authType"],"properties":{"authType":{"const":"awsIam"}}}}},"then":{"required":["_iClientId"],"properties":{"redshift":{"oneOf":[{"required":["clusterIdentifier"],"not":{"required":["workgroupName"]}},{"required":["workgroupName"],"not":{"required":["clusterIdentifier"]}}]}}},"else":{"properties":{"redshift":{"required":["aws","clusterIdentifier"],"not":{"required":["workgroupName"]},"properties":{"aws":{"required":["accessKeyId","secretAccessKey"]}}}}}}}}}}}}},"MongoDB":{"type":"object","description":"Configuration for MongoDB connections. Used when the connection type is \"mongodb\". Supports\nstandalone instances, replica sets, and MongoDB Atlas clusters. For a replica set, list all\nmember addresses in host and set replicaSet to the set name; authSource selects the\nauthentication database when it differs from the target database.","required":["host","username","password"],"properties":{"host":{"type":"array","minItems":1,"items":{"type":"string"},"description":"MongoDB server addresses. An array of one or more host:port strings.\n\n- Standalone: [\"mongodb.example.com:27017\"]\n- Replica set: [\"rs1.example.com:27017\", \"rs2.example.com:27017\", \"rs3.example.com:27017\"]\n- MongoDB Atlas: [\"cluster0-shard-00-00.abc.mongodb.net:27017\", ...]\n\nInclude the port number with each host. Default MongoDB port is 27017.\n"},"database":{"type":"string","description":"Target MongoDB database name.\nAll operations (reads/writes) target collections within this database.\nOptional on the connection — when omitted, set the database per operation instead.\n"},"username":{"type":"string","description":"MongoDB username for authentication."},"password":{"type":"string","writeOnly":true,"description":"MongoDB password. Write-only — accepted on create/update and returned masked as `\"******\"`."},"replicaSet":{"type":"string","description":"MongoDB replica set name. Set this when connecting to a replica set so the driver can\ndiscover all members and handle failover. For MongoDB Atlas, this is typically\n\"atlas-xxxxxx-shard-0\".\n"},"ssl":{"type":"boolean","description":"When true, connects to MongoDB over TLS/SSL.\nRequired for MongoDB Atlas and recommended for all production deployments.\n","default":false},"authSource":{"type":"string","description":"MongoDB authentication database — the database where the user credentials are stored.\nDefaults to the value of the database field. Set to \"admin\" if the user was created\nin the admin database (common for shared MongoDB deployments and Atlas).\n"},"concurrencyLevel":{"type":"integer","description":"Maximum number of concurrent MongoDB operations.\nSend no more than the account's licensed maximum (25 standard, 50 with an Environments license).\n","minimum":1,"maximum":50,"default":5},"targetConcurrencyLevel":{"type":"integer","description":"Target concurrency level for auto-scaling. The system adjusts concurrency\nbetween 1 and this value based on rate limit feedback.\n\nOnly relevant when autoRecoverRateLimitErrors is enabled on the connection.\n","minimum":1,"maximum":50,"default":5}}},"AS2":{"type":"object","description":"AS2 (Applicability Statement 2) connection configuration for EDI","required":["as2Id","partnerId","partnerStationInfo","userStationInfo"],"properties":{"as2Id":{"type":"string","description":"AS2 identifier for this station. Trading partners use this as the \"To\"\nidentifier when sending documents, and integrator.io uses it as the \"From\"\nidentifier when sending documents to partners.\n\nMust be unique across ALL integrator.io users so inbound documents route\ncorrectly. Set on creation and cannot be changed afterward — a PUT with a\ndifferent value is ignored. Use a distinct identifier per environment\n(e.g. production vs. non-production). If omitted, a unique value is auto-generated.\n"},"partnerId":{"type":"string","description":"Trading partner's AS2 identifier — the partner's \"From\" identifier on documents they\nsend and the \"To\" identifier integrator.io uses when sending to them. Set on creation\nand cannot be changed afterward; a PUT with a different value is ignored."},"_tpConnectorId":{"type":"string","format":"objectId","description":"Trading partner connector this AS2 connection was provisioned from during partner onboarding. Omit for a standalone AS2 connection."},"contentBasedFlowRouter":{"type":"object","description":"Routes inbound documents to different flows based on message content, for connections\nshared across multiple flows. Omit unless a routing script is required.","properties":{"function":{"type":"string","description":"Function in the routing script that returns the target flow."},"_scriptId":{"type":"string","format":"objectId","description":"Script containing the routing function named in `function`."}}},"partnerStationInfo":{"type":"object","description":"Partner (remote) station configuration, used on the IMPORT side — controls how messages\nare sent TO the trading partner.","required":["as2URI","signing","encryptionType"],"properties":{"as2URI":{"type":"string","format":"uri","description":"Partner's AS2 endpoint that integrator.io posts outbound messages to.\n\nUse an HTTPS URL whenever possible. HTTP is not considered a secure protocol; data\nsent to an HTTP endpoint is not encrypted and may be intercepted or modified in transit."},"mdn":{"type":"object","description":"Settings for the MDN (Message Disposition Notification) receipt the partner returns for outbound messages.","required":["mdnSigning"],"properties":{"mdnURL":{"type":"string","format":"uri","description":"Endpoint the partner posts asynchronous MDNs to. Set only when the partner\nreturns MDNs asynchronously rather than on the same connection.\n\nUse an HTTPS URL whenever possible. HTTP is not considered a secure protocol;\ndata sent to an HTTP endpoint is not encrypted and may be intercepted or\nmodified in transit."},"signatureProtocol":{"type":"string","enum":["pkcs7-signature"],"description":"Signature protocol the partner uses on returned MDNs."},"mdnSigning":{"type":"string","enum":["NONE","SHA1","MD5","SHA256"],"description":"Hash algorithm used to verify the signature on MDNs the partner returns. Defaults to NONE when the partner does not sign MDNs."},"verifyMDNSignature":{"type":"boolean","description":"When true, verifies the signature on MDNs returned by the partner. Requires unencrypted.partnerCertificate."}}},"auth":{"type":"object","description":"Authentication for posting messages to the partner's AS2 endpoint. Omit (or set\ntype to none) when the endpoint is unauthenticated.","properties":{"type":{"type":"string","enum":["basic","token","none"],"description":"Authentication scheme for the partner endpoint. Set the matching basic or token sub-object for basic or token."},"failStatusCode":{"type":"number","description":"HTTP status code in the partner's response that signals an authentication failure, triggering a token refresh or error."},"failPath":{"type":"string","description":"Path in the partner's JSON response body checked against failValues to detect an authentication failure."},"failValues":{"type":"array","items":{"type":"string"},"description":"Values at failPath that indicate an authentication failure. Requires failPath."},"basic":{"type":"object","description":"Credentials for basic authentication. Present when type is basic.","properties":{"username":{"type":"string","description":"Username for basic authentication."},"password":{"type":"string","writeOnly":true,"description":"Password for basic authentication. Masked as \"******\" in GET responses."}}},"token":{"type":"object","description":"Token configuration. Present when type is token.","properties":{"token":{"type":"string","writeOnly":true,"description":"Bearer/access token sent with each request to the partner. Masked as \"******\" in GET responses."},"location":{"type":"string","enum":["header","url","body"],"description":"Where to place the token in the outbound request."},"headerName":{"type":"string","description":"Header name carrying the token when location is header. Defaults to Authorization."},"scheme":{"type":"string","enum":["bearer","mac","oauth","none"],"description":"Authorization scheme prepended to the token when location is header."},"paramName":{"type":"string","description":"Query parameter name carrying the token when location is url."},"refreshToken":{"type":"string","writeOnly":true,"description":"Token used to obtain a new access token when the current one expires. Masked as \"******\" in GET responses."},"refreshRelativeURI":{"type":"string","description":"Endpoint, relative to the partner's host, called to refresh the token."},"refreshMethod":{"type":"string","enum":["GET","POST","PUT"],"description":"HTTP method for the token-refresh request."},"refreshMediaType":{"type":"string","enum":["json","urlencoded","xml"],"description":"Content type of the token-refresh request body."},"refreshBody":{"type":"string","description":"Request body sent with the token-refresh request, used when refreshMethod is POST or PUT."},"refreshTokenPath":{"type":"string","description":"Path in the refresh response body where the new access token is found."},"refreshHeaders":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"Header name to send with the token-refresh request."},"value":{"type":"string","description":"Header value to send with the token-refresh request."}}},"description":"Headers sent with the token-refresh request."}}}}},"rateLimit":{"type":"object","description":"Throttles requests to the partner endpoint when it enforces a non-standard rate limit.","properties":{"failStatusCode":{"type":"number","description":"HTTP status code in the partner's response that indicates rate limiting."},"failPath":{"type":"string","description":"Path in the partner's JSON response body checked against failValues to detect rate limiting."},"failValues":{"type":"array","description":"Values at failPath that indicate rate limiting. Requires failPath.","items":{"type":"string"}},"limit":{"type":"number","minimum":1,"description":"Wait time in milliseconds between requests to the partner endpoint."}}},"SMIMEVersion":{"type":"string","enum":["v2","v3"],"description":"S/MIME version applied to outbound messages. Not exposed in the connection form."},"signing":{"type":"string","enum":["NONE","SHA1","MD5","SHA256"],"description":"Hash algorithm for signing messages sent to the partner. Any value other than NONE requires encrypted.userPrivateKey and unencrypted.userPublicKey."},"encryptionType":{"type":"string","enum":["NONE","DES","RC2","3DES","AES128","AES256"],"description":"Cipher for encrypting messages sent to the partner. Any value other than NONE requires unencrypted.partnerCertificate."},"encoding":{"type":"string","enum":["base64","binary"],"description":"Content transfer encoding for outbound messages. Shown in the form only when encryptionType is not NONE."},"signatureEncoding":{"type":"string","enum":["base64","binary"],"description":"Encoding applied to the digital signature on outbound messages."}}},"userStationInfo":{"type":"object","description":"User (local) station configuration, used on the EXPORT side — controls how inbound\nmessages from the partner are processed.","required":["signing","encryptionType"],"properties":{"mdn":{"type":"object","description":"Settings for the MDN receipt this station returns to the partner for inbound messages.","required":["mdnSigning"],"properties":{"mdnURL":{"type":"string","anyOf":[{"format":"uri"},{"const":""}],"description":"Partner's endpoint this station posts asynchronous MDNs to. Set only when\nthe partner requires asynchronous MDNs; stored as an empty string otherwise.\n\nUse an HTTPS URL whenever possible. HTTP is not considered a secure protocol;\ndata sent to an HTTP endpoint is not encrypted and may be intercepted or\nmodified in transit."},"signatureProtocol":{"type":"string","enum":["pkcs7-signature"],"description":"Signature protocol applied to MDNs this station returns."},"mdnSigning":{"type":"string","enum":["NONE","SHA1","MD5","SHA256"],"description":"Hash algorithm used to sign MDNs this station returns to the partner. Signs the MDN\nonly — the hash algorithm of its `Received-Content-MIC` follows\nuserStationInfo.signing, not this field."},"mdnEncoding":{"type":"string","enum":["base64","binary"],"description":"Encoding applied to MDNs this station returns."}}},"signing":{"type":"string","enum":["NONE","SHA1","MD5","SHA256"],"description":"Hash algorithm for verifying signatures on inbound messages; the same algorithm is used\nfor the `Received-Content-MIC` in the MDN returned for each message (NONE falls back to\nSHA-1, and the algorithm the partner requests in `Disposition-Notification-Options` is\nnot used). The MIC is computed when a message is received, so a change here applies only\nto messages received afterwards — the partner must resend to get an MDN with the new\nalgorithm. Any value other than NONE requires unencrypted.partnerCertificate."},"encryptionType":{"type":"string","enum":["NONE","DES","RC2","3DES","AES128","AES256"],"description":"Cipher for decrypting inbound messages. Any value other than NONE requires encrypted.userPrivateKey and unencrypted.userPublicKey."},"encoding":{"type":"string","enum":["base64","binary"],"description":"Content transfer encoding expected on inbound messages. Shown in the form only when encryptionType is not NONE."},"compressed":{"type":"boolean","description":"When true, message content is compressed. Not exposed in the connection form.","default":false}}},"encrypted":{"type":"object","description":"Encrypted-at-rest key material for this station's own identity. Supply when this station\nsigns outbound messages or decrypts inbound messages; integrator.io injects an\nauto-generated self-signed key otherwise.","properties":{"userPrivateKey":{"type":"string","writeOnly":true,"description":"PEM-encoded X.509 private key for this station, used to sign outbound messages and\ndecrypt inbound ones. Masked as \"******\" in GET responses. Required when\npartnerStationInfo.signing is not NONE or userStationInfo.encryptionType is not NONE."}}},"unencrypted":{"type":"object","description":"Public certificate material for this station and the partner. integrator.io injects an\nauto-generated self-signed certificate for this station when none is supplied.","properties":{"userPublicKey":{"type":"string","description":"PEM-encoded X.509 public certificate for this station, paired with\nencrypted.userPrivateKey. Required when partnerStationInfo.signing is not NONE or\nuserStationInfo.encryptionType is not NONE."},"partnerCertificate":{"type":"string","description":"PEM-encoded X.509 certificate for the trading partner, used to encrypt outbound\nmessages and verify inbound signatures and MDNs. Required when\npartnerStationInfo.encryptionType is not NONE, userStationInfo.signing is not NONE,\nor partnerStationInfo.mdn.verifyMDNSignature is true."}}},"concurrencyLevel":{"type":"integer","description":"Maximum number of messages processed concurrently for this connection. The default of 5\nis safe for most partners. Send no more than the account's licensed maximum (25 standard,\n50 with an Environments license).","minimum":1,"maximum":50,"default":5},"targetConcurrencyLevel":{"type":"integer","description":"Concurrency ceiling integrator.io scales up to when auto-recovering from rate-limit\nerrors. Only applies when autoRecoverRateLimitErrors is true on the connection.","minimum":1,"maximum":50},"preventCanonicalization":{"type":"boolean","description":"When true, inbound messages are verified — and the `Received-Content-MIC` in the returned\nMDN is computed — over the content exactly as received, without first normalizing line\nendings to CRLF; the partner's MDN signatures are verified the same way. Enable only when a\npartner reports signature-verification failures or MIC mismatches caused by\ncanonicalization.","default":false}}},"Filesystem":{"type":"object","description":"Configuration for filesystem connections. Used when the connection type is \"filesystem\".\nProvides access to directories on a Celigo on-premise Agent's host or mounted network\ndrives, so a connection-level `_agentId` is required — cloud-only deployments cannot use\nthis type. File-based PGP encryption/decryption is configured through the connection-level\n`pgp` object.","properties":{"ping":{"type":"object","description":"Connection health-check configuration. integrator.io reads this directory to verify the agent can reach the filesystem.","properties":{"directoryPath":{"type":"string","description":"Absolute directory path the agent checks to confirm filesystem access. Accepts a POSIX path,\na Windows drive path, or a UNC share. Leave unset to skip the directory check during ping."}}},"concurrencyLevel":{"type":"integer","description":"Maximum number of files processed concurrently. Send no more than `targetConcurrencyLevel` and\nthe account's licensed maximum (25 standard, 50 with an Environments license).","minimum":1,"maximum":50,"default":1},"targetConcurrencyLevel":{"type":"integer","description":"Upper bound for auto-scaling. The agent scales concurrency between 1 and this value based on\nthroughput, so it also caps `concurrencyLevel`. Send no more than the account's licensed maximum\n(25 standard, 50 with an Environments license).","minimum":1,"maximum":50,"default":1}}},"MCP":{"type":"object","description":"Configuration for MCP (Model Context Protocol) connections. Used when the connection type\nis \"mcp\". Lets Celigo call tools exposed by an external MCP server over HTTP. Authentication\ngoes through the http sub-object, which reuses the HTTP auth config but accepts only the\ntoken, oauth, and custom auth types.","required":["serverURL","http"],"properties":{"protocol":{"type":"string","enum":["http"],"default":"http","readOnly":true,"description":"Transport protocol for communicating with the MCP server.\nCurrently only \"http\" is supported; the server sets this automatically and ignores other values.\n"},"serverURL":{"type":"string","format":"uri","description":"MCP server endpoint URL. Must be a valid absolute URL\n(e.g. \"https://mcp-server.example.com/mcp\").\n\nUse an HTTPS URL whenever possible. HTTP is not considered a secure protocol; data sent\nto an HTTP endpoint is not encrypted and may be intercepted or modified in transit."},"timeout":{"type":"number","default":600000,"description":"Request timeout in milliseconds for MCP tool invocations.\nIf the MCP server does not respond within this time, the request fails.\nDefaults to 600000 (10 minutes) when omitted.\n"},"allowedTools":{"type":"array","description":"Optional allowlist of MCP tool names that this connection may invoke.\nWhen set, only tools in this list can be called. When omitted or empty,\nall tools exposed by the MCP server are available.\n","items":{"type":"string"}},"http":{"type":"object","required":["auth"],"description":"HTTP transport configuration for the MCP connection, including authentication and headers.\n","properties":{"_iClientId":{"type":"string","format":"objectId","description":"Reference to an OAuth iClient for OAuth-based MCP authentication.\nRequired when http.auth.type is \"oauth\".\n"},"auth":{"type":"object","required":["type"],"description":"Authentication configuration for the MCP connection. The auth.type field selects the\nstrategy. MCP supports only token, oauth, and custom — other HTTP auth types\n(basic, wsse, cookie, jwt, etc.) are rejected with a 422.\n","properties":{"type":{"type":"string","enum":["token","oauth","custom"],"description":"Authentication method for the MCP server. Determines which auth sub-fields apply."},"token":{"$ref":"#/components/schemas/token"},"oauth":{"$ref":"#/components/schemas/OAuth"}}},"headers":{"type":"array","description":"Default HTTP headers included in every request to the MCP server.\n","items":{"type":"object","properties":{"name":{"type":"string","description":"Header name."},"value":{"type":"string","description":"Header value. Supports handlebars expressions for dynamic values."}},"required":["name","value"]}},"unencrypted":{"type":"object","description":"Unencrypted custom fields for non-sensitive MCP configuration."},"encrypted":{"type":["object","string"],"description":"Encrypted custom fields for sensitive MCP configuration. Sent as an object;\nreturned as the masked string `\"******\"` on responses."}},"if":{"properties":{"auth":{"properties":{"type":{"const":"token"}},"required":["type"]}},"required":["auth"]},"then":{"properties":{"auth":{"required":["token"],"properties":{"token":{"required":["token"]}}}}},"else":{"if":{"properties":{"auth":{"properties":{"type":{"const":"oauth"}},"required":["type"]}},"required":["auth"]},"then":{"required":["_iClientId"]}}}}},"token":{"type":"object","description":"Token-based authentication configuration. Required when auth.type is \"token\".\n\nSupports static API keys/bearer tokens and automatic token refresh flows.\nThe token can be sent in a header (Authorization), query parameter, or request body.\n","properties":{"token":{"type":"string","description":"The API key or bearer token value (encrypted at rest); returned masked as `\"******\"`.\nOn update, the mask sent back keeps the stored token; a new value replaces it.\nRequired unless automatic token refresh is configured: a token block without a\ntoken must carry a `refreshMethod`, so a create or update that sends neither fails\nwith 422 `Expected field: refreshMethod to be present.` To create a static-token\nconnection before the real token is available, send a placeholder value and\nreplace it later.\n"},"location":{"type":"string","enum":["url","header","body"],"description":"Where to include the token in outbound requests.\nMost APIs expect header. Use headerName and scheme to control the header format,\nor paramName when sending as a URL query parameter."},"headerName":{"type":"string","description":"HTTP header name for the token when location is \"header\".\nDefaults to \"Authorization\" if omitted.\n"},"scheme":{"type":"string","description":"Token scheme/prefix when sent in a header. Prepended before the token value.\nCommon values: \"Bearer\", \"Token\", \"Basic\".\nExample: scheme \"Bearer\" produces header \"Authorization: Bearer <token>\".\n"},"paramName":{"type":"string","description":"Query parameter name for the token when location is \"url\".\nExample: paramName \"api_key\" produces URL \"?api_key=<token>\".\n"},"refreshMethod":{"type":"string","enum":["GET","POST","PUT"],"description":"HTTP method for automatic token refresh requests.\nRequired when no static token is provided (refresh-based auth flow).\n","default":"POST"},"refreshRelativeURI":{"type":"string","description":"Relative URI (appended to baseURI) for the token refresh endpoint.\nThe system calls this endpoint to obtain a new token when the current one expires.\n"},"refreshBody":{"type":"string","description":"Request body to send with the token refresh request."},"refreshMediaType":{"type":"string","enum":["json","urlencoded","xml","plaintext"],"description":"Content type for the token refresh request body.\n","default":"urlencoded"},"refreshResponseMediaType":{"type":"string","enum":["json","xml"],"description":"Expected content type of the token refresh response."},"refreshTokenPath":{"type":"string","description":"JSON path to extract the new token from the refresh response.\nExample: \"access_token\" or \"data.token\".\n"},"refreshToken":{"type":"string","description":"Refresh token used to obtain a new access token (encrypted at rest).","writeOnly":true},"refreshTokenLocation":{"type":"string","enum":["header","body"],"description":"Where to include the refresh token in refresh requests."},"refreshHeaders":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"Header name to send with the token-refresh request."},"value":{"type":"string","description":"Header value to send with the token-refresh request."}}},"description":"Additional headers to include in token refresh requests."},"tokenPaths":{"type":"array","items":{"type":"string"},"description":"JSON paths to extract multiple token values from the refresh response.\nUse when the refresh response contains tokens at different paths that need\nto be stored for subsequent requests.\n"},"revoke":{"type":"object","description":"Token-revocation request configuration. When set, the system calls this\nendpoint to revoke the current token (e.g. when the connection is deleted or\nre-authenticated). Used mainly by pre-built HTTP Connector templates.\n","properties":{"uri":{"type":"string","description":"Absolute URL of the token-revocation endpoint."},"body":{"type":"string","description":"Request body to send with the token-revocation request."},"headers":{"type":"array","description":"Additional headers to include in the token-revocation request.","items":{"type":"object","properties":{"name":{"type":"string","description":"Header name to send with the revocation request."},"value":{"type":"string","description":"Header value to send with the revocation request."}}}}}}}},"DynamoDB":{"type":"object","description":"Configuration for Amazon DynamoDB connections. Used when the connection type is \"dynamodb\".\nAuthenticates with AWS IAM access keys, which must grant the DynamoDB actions the integration\nuses (GetItem, PutItem, Query, Scan, etc.). The AWS region is resolved per table at request\ntime, so no region is stored on the connection.","required":["aws"],"properties":{"aws":{"type":"object","description":"AWS IAM access-key credentials used to sign DynamoDB requests.","required":["accessKeyId","secretAccessKey"],"properties":{"accessKeyId":{"type":"string","description":"Access key ID of the IAM user or role whose policy grants the required DynamoDB actions."},"secretAccessKey":{"type":"string","description":"Secret access key paired with `accessKeyId`. Encrypted at rest and returned masked as `\"******\"`.","writeOnly":true}}},"concurrencyLevel":{"type":"integer","description":"Maximum number of DynamoDB requests this connection runs at once.\n\nSend no more than the account's licensed maximum (25 standard, 50 with an Environments license).","minimum":1,"maximum":50,"default":5},"targetConcurrencyLevel":{"type":"integer","description":"Concurrency ceiling for auto-scaling. The system adjusts the active concurrency between 1\nand this value based on rate-limit feedback. Only applied when `autoRecoverRateLimitErrors`\nis enabled on the connection. The same licensed maximum applies as for `concurrencyLevel`.","minimum":1,"maximum":50,"default":5}}},"JDBC":{"type":"object","description":"Configuration for JDBC (Java Database Connectivity) connections. Used when the connection\ntype is \"jdbc\". Provides access through Java JDBC drivers to databases not covered by the\nrdbms type — such as NetSuite SuiteAnalytics, Databricks, DB2, and Workday. The driver runs\non a Celigo on-premise Agent, so most jdbc connections need a connection-level _agentId.","required":["type"],"properties":{"type":{"type":"string","enum":["agent","netsuitejdbc","databricks","oracle:thin","sqlserver","activedirectory","db2","workday"],"description":"JDBC driver/connection type. Selects which JDBC driver is used and determines\nthe required fields. Most JDBC connections require a Celigo on-premise Agent."},"version":{"type":"string","description":"JDBC driver version. Used for driver compatibility when multiple versions are available."},"host":{"type":"string","description":"Database server hostname or IP address.\nFor NetSuite JDBC, use the SuiteAnalytics Connect hostname\n(e.g., \"account-id.connect.api.netsuite.com\").\n"},"port":{"type":"number","description":"Database server port number. Default varies by driver type."},"database":{"type":"string","description":"Database or catalog name. For Oracle, use the serviceName field instead.\n"},"user":{"type":"string","description":"Database username for authentication."},"password":{"type":"string","description":"Database password (encrypted at rest).","writeOnly":true},"serviceName":{"type":"string","description":"Oracle service name. Used instead of the database field for Oracle JDBC connections.\nThis is the TNS service name or pluggable database (PDB) service name.\n"},"authType":{"type":"string","enum":["customjdbc","wallet"],"description":"Authentication method for the JDBC connection. Defaults to customjdbc (username/password).\nUse wallet for Oracle Wallet authentication with the wallet field."},"wallet":{"type":"string","description":"Oracle Wallet file contents (encrypted at rest).\nRequired when authType is \"wallet\". Contains the auto-login wallet (cwallet.sso)\nwith encrypted credentials for passwordless Oracle authentication.\n","writeOnly":true},"driverPath":{"type":"string","description":"File path to the JDBC driver JAR on the Celigo Agent.\nRequired when type is \"agent\" (generic JDBC).\nThe driver must be deployed on the agent before creating the connection.\n"},"properties":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"JDBC connection property name (driver-specific)."},"value":{"type":"string","description":"JDBC connection property value."}}},"description":"Additional JDBC connection properties as name/value pairs.\nThese are passed directly to the JDBC driver as connection properties.\nUse for driver-specific settings like SSL mode, connection timeout,\napplication name, etc.\n"},"concurrencyLevel":{"type":"integer","description":"Maximum number of concurrent database connections.\nJDBC connections often run through a single Agent, so keep this value\nconservative to avoid overwhelming the Agent or database.\nSend no more than the account's licensed maximum (25 standard, 50 with an Environments license).\n","minimum":1,"maximum":50,"default":5},"targetConcurrencyLevel":{"type":"integer","description":"Target concurrency level for auto-scaling. The system adjusts the number of\nconcurrent connections between 1 and this value based on performance feedback.\n","minimum":1,"maximum":50,"default":5}},"if":{"properties":{"type":{"const":"db2"}},"required":["type"]},"then":{"required":["host","user","password","database","port","properties"]},"else":{"if":{"properties":{"type":{"const":"oracle:thin"}},"required":["type"]},"then":{"required":["user","password","authType"],"if":{"properties":{"authType":{"const":"wallet"}},"required":["authType"]},"then":{"required":["wallet","serviceName"]},"else":{"required":["host"]}},"else":{"if":{"properties":{"type":{"const":"activedirectory"}},"required":["type"]},"then":{"required":["host","port","user","password","properties"]},"else":{"if":{"properties":{"type":{"const":"netsuitejdbc"}},"required":["type"]},"then":{"required":["host","user","properties"]},"else":{"if":{"properties":{"type":{"const":"agent"}},"required":["type"]},"then":{"required":["host","driverPath"]},"else":{"if":{"properties":{"type":{"const":"workday"}},"required":["type"]},"then":{"required":["host","user","password","properties"]},"else":{"if":{"properties":{"type":{"const":"databricks"}},"required":["type"]},"then":{"required":["host"]}}}}}}}},"VAN":{"type":"object","description":"Configuration for VAN (Value-Added Network) connections. Used when the connection type is \"van\".\nA VAN connection exchanges EDI documents through a managed network mailbox; outbound documents are\nposted to the mailbox and inbound documents are picked up from it, addressed by the connection's AS2 identifier.","properties":{"as2Id":{"type":"string","description":"AS2 identifier for this VAN station — the \"From\" identifier on outbound documents and the \"To\"\nidentifier on inbound. Must be unique across all integrator.io VAN connections; a duplicate fails\nthe create. Set once when the connection is created and cannot be changed afterward (writes on update\nare ignored). Omit it to have the network assign one automatically."},"mailboxId":{"type":"number","readOnly":true,"description":"Numeric mailbox identifier assigned by the VAN provider when the connection is provisioned.\nServer-assigned and not writable — values sent on create or update are ignored."},"contentBasedFlowRouter":{"type":"object","description":"Routes inbound documents to different flows based on message content, for a connection shared across\nmultiple flows. The named function in the referenced script inspects each incoming document and returns\nthe flow to run. Omit to disable content-based routing.","properties":{"function":{"type":"string","description":"Function in the referenced script that returns the target flow for each inbound document."},"_scriptId":{"type":"string","format":"objectId","description":"ID of the script resource that contains the routing function. Must reference an existing script; an unknown ID fails the request with 422 `invalid_ref`."}}}}},"Wrapper":{"type":"object","description":"Configuration for Wrapper connections. Used when the connection type is \"wrapper\". A wrapper\nis a fully custom connector implemented in server-side JavaScript on a Celigo Stack\n(referenced by _stackId) — use it when the target API needs\nnon-standard authentication or logic that HTTP connections can't express. Connection-specific\nvalues go in the encrypted/unencrypted fields, which the wrapper code reads at runtime.","required":["pingFunction"],"properties":{"pingFunction":{"type":"string","description":"Name of the JavaScript function on the Stack that tests connection health, invoked when\n\"Test Connection\" is clicked. It should verify the credentials are valid and the target\nsystem is reachable."},"unencrypted":{"type":"object","description":"Unencrypted custom fields for non-sensitive configuration values.\nThese values are accessible to the wrapper code on the Stack at runtime.\nField definitions are specified in unencryptedFields.\n"},"unencryptedFields":{"type":"array","description":"Metadata defining the unencrypted custom fields on this connection.","items":{"type":"object","properties":{"id":{"type":"string","description":"Field identifier — matches the key in the unencrypted object."},"label":{"type":"string","description":"Human-readable label shown in the UI."},"required":{"type":"boolean","default":false,"description":"When true, the custom field defined by this entry is mandatory — a value for it must be supplied before the connection can be saved."},"position":{"type":"number","description":"Display order in the UI form."},"helpText":{"type":"string","description":"Tooltip text shown next to the field in the UI."},"type":{"type":"string","description":"Optional, legacy field-type hint. The wrapper form ignores it — it always renders these\ncustom fields as text inputs — so it is rarely set."}}}},"encrypted":{"type":["object","string"],"description":"Encrypted custom fields for sensitive configuration values (API keys, passwords, etc.).\nSent as an object of field-name/value pairs; values are encrypted at rest and decrypted\nonly on the Stack at runtime. Returned as the masked string `\"******\"` on responses.\nField definitions are specified in encryptedFields.\n"},"encryptedFields":{"type":"array","description":"Metadata defining the encrypted custom fields on this connection.","items":{"type":"object","properties":{"id":{"type":"string","description":"Field identifier — matches the key in the encrypted object."},"label":{"type":"string","description":"Human-readable label shown in the UI."},"required":{"type":"boolean","default":false,"description":"When true, the custom field defined by this entry is mandatory — a value for it must be supplied before the connection can be saved."},"position":{"type":"number","description":"Display order in the UI form."},"helpText":{"type":"string","description":"Tooltip text shown next to the field in the UI."},"type":{"type":"string","description":"Optional, legacy field-type hint. The wrapper form ignores it — it always renders these\ncustom fields as text inputs (masked) — so it is rarely set."}}}},"_stackId":{"type":"string","format":"objectId","description":"Reference to the Celigo Stack whose server-side JavaScript implements this connection."},"concurrencyLevel":{"type":"integer","description":"Maximum number of concurrent operations through this wrapper connection.\nSend no more than the account's licensed maximum (25 standard, 50 with an Environments license).\n","minimum":1,"maximum":50,"default":5},"targetConcurrencyLevel":{"type":"integer","description":"Target concurrency level for auto-scaling. The system adjusts concurrency\nbetween 1 and this value based on performance feedback.\n","minimum":1,"maximum":50}}},"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"}}}}}},"paths":{"/v1/endusers/connections/{_connectionId}":{"get":{"summary":"Get an end user's connection","operationId":"getEndUserConnection","tags":["End Users"],"description":"Returns one `mcpChild` connection — the credentials an end user supplied\nfor a connection that an MCP server flagged `requiresEndUserCredentials`.\nCredentials are masked as on every connection read; there is no unmasked\nform. Only children resolve here: a standard connection id answers 404\nexactly like an unknown id, and the generic `GET /v1/connections/{_id}`\nanswers 404 for a child. No MCP server appears in the path because a\nchild is keyed by its parent connection and end user, not by server —\ndiscover ids with `GET /v1/mcpservers/{_id}/connections?connectionRole=mcpChild`.\nOn the returned document `_userId` is the end user who owns it and\n`_mcpOwnerId` is the account. Requires account owner or administrator\naccess.","parameters":[{"name":"_connectionId","in":"path","required":true,"description":"Id of the `mcpChild` connection.","schema":{"type":"string","format":"objectId"}}],"responses":{"200":{"description":"The `mcpChild` connection, credentials masked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Connection"}}}},"400":{"description":"The path segment is not a valid connection id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"403":{"$ref":"#/components/responses/403-forbidden"},"404":{"description":"No `mcpChild` connection with this id on the account — also returned for a standard connection id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}
```

## Delete an end user's connection

> Soft-deletes one \`mcpChild\` connection, so the end user must connect\
> again before using tools that run through its parent. This is the only\
> delete path for a child — the generic connection routes answer 404 for\
> one — and, by the platform contract, a deleted child is not restorable\
> from the recycle bin. A standard connection id answers 404 exactly like\
> an unknown id. Requires account owner or administrator access; the end\
> user who owns the child cannot call it.

```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, inspect the effective MCP access\n(tools, APIs, prompts, and resources) compiled from their grants,\ngroups, and roles, and read or delete the `mcpChild` connections that\nhold the credentials they supplied for connections flagged\n`requiresEndUserCredentials`. An end user's access record is an\nashare, so editing its grants and suspending it use the `/v1/ashares`\nroutes shared with workspace users. The account owner is never an end\nuser: owners already have MCP access without an end-user record, the\ninvite refuses the owner's address (`owner_self_invite_not_allowed`),\nand the owner never appears in these lists. Workspace administrators\nneed no record either: under Celigo OAuth they reach every MCP server in\nthe environment, and everything on it. Other workspace users need an\nend-user record with grants. Anyone who also holds an end-user record,\nan administrator included, is judged by that record's grants.\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":{"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"}}}}}},"paths":{"/v1/endusers/connections/{_connectionId}":{"delete":{"summary":"Delete an end user's connection","operationId":"deleteEndUserConnection","tags":["End Users"],"description":"Soft-deletes one `mcpChild` connection, so the end user must connect\nagain before using tools that run through its parent. This is the only\ndelete path for a child — the generic connection routes answer 404 for\none — and, by the platform contract, a deleted child is not restorable\nfrom the recycle bin. A standard connection id answers 404 exactly like\nan unknown id. Requires account owner or administrator access; the end\nuser who owns the child cannot call it.","parameters":[{"name":"_connectionId","in":"path","required":true,"description":"Id of the `mcpChild` connection.","schema":{"type":"string","format":"objectId"}}],"responses":{"204":{"description":"Connection deleted."},"400":{"description":"The path segment is not a valid connection id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"403":{"$ref":"#/components/responses/403-forbidden"},"404":{"description":"No `mcpChild` connection with this id on the account — also returned for a standard connection id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}
```

## 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, inspect the effective MCP access\n(tools, APIs, prompts, and resources) compiled from their grants,\ngroups, and roles, and read or delete the `mcpChild` connections that\nhold the credentials they supplied for connections flagged\n`requiresEndUserCredentials`. An end user's access record is an\nashare, so editing its grants and suspending it use the `/v1/ashares`\nroutes shared with workspace users. The account owner is never an end\nuser: owners already have MCP access without an end-user record, the\ninvite refuses the owner's address (`owner_self_invite_not_allowed`),\nand the owner never appears in these lists. Workspace administrators\nneed no record either: under Celigo OAuth they reach every MCP server in\nthe environment, and everything on it. Other workspace users need an\nend-user record with grants. Anyone who also holds an end-user record,\nan administrator included, is judged by that record's grants.\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 person's group in\nthe identity provider instead (its group mapping, or the SCIM group\nassignment, whichever created the membership)."}}},"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. Each `:all` capability\ncovers only its own kind — grant `tool:all`, `api:all`, `prompt:all`,\nand `resource:all` together to open every item on a server.","items":{"type":"string","pattern":"^(?:tool|api|prompt|resource):(?:[a-fA-F0-9]{24}|all)$|^pset:[a-fA-F0-9]{24}$","description":"Capability string for an `mcpServer` grant. `tool:`, `api:`,\n`prompt:`, and `resource:` take `all` or a 24-hex id on the target\nserver — a `tools[]._toolId` or upstream tool row `_id`, an\n`apis[]._apiId`, a `prompts[]._id`, or a `resources[]._id`; `pset:`\ntakes a `permissionSets[]._id`. Grant prompts with `prompt:<_id>`:\nolder grants written as `tool:<prompt _id>` still validate but are\nnot reported by effective access. Any other shape is rejected with\n400 `validation_failed` (\"Invalid capability\"), and an id that is\nnot attached to the target server with 400 `validation_failed`\nnaming the missing item."}}}},"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","scim"],"description":"How this end-user record was created. A SCIM push for a person who already has an invited\nor JIT record adopts it in place, so the value can change to `scim` over the record's life.\nFor a SCIM-managed user the identity provider owns the active state and the IdP-sourced\ngroup memberships and roles: `PUT /v1/ashares/{_ashareId}/disable` still toggles `disabled`,\nbut the identity provider's next push re-applies what it holds — deactivate the person or\nchange their groups in the IdP. Direct `resourceGrants` and `manual` memberships are never\ntouched by SCIM."},"externalId":{"type":"string","readOnly":true,"description":"Identifier the identity provider uses for this person in its own directory,\nstored when the record is provisioned through SCIM. Present only when\n`provisionedBy` is `scim`. SCIM matches people by email, not by this value."},"_scimIdpConfigId":{"type":"string","format":"objectId","readOnly":true,"description":"IdP configuration whose SCIM endpoint provisioned this record. Present\nonly when `provisionedBy` is `scim`."},"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, inspect the effective MCP access\n(tools, APIs, prompts, and resources) compiled from their grants,\ngroups, and roles, and read or delete the `mcpChild` connections that\nhold the credentials they supplied for connections flagged\n`requiresEndUserCredentials`. An end user's access record is an\nashare, so editing its grants and suspending it use the `/v1/ashares`\nroutes shared with workspace users. The account owner is never an end\nuser: owners already have MCP access without an end-user record, the\ninvite refuses the owner's address (`owner_self_invite_not_allowed`),\nand the owner never appears in these lists. Workspace administrators\nneed no record either: under Celigo OAuth they reach every MCP server in\nthe environment, and everything on it. Other workspace users need an\nend-user record with grants. Anyone who also holds an end-user record,\nan administrator included, is judged by that record's grants.\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"}}}}}}}}}
```
