connectors 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +35 -0
- data/CONNECTORS_FRAMEWORK.md +799 -0
- data/CONTRIBUTING.md +60 -0
- data/MCP_CLIENT.md +168 -0
- data/MIT-LICENSE +20 -0
- data/README.md +146 -0
- data/app/connectors/clickup/connector.rb +13 -0
- data/app/connectors/gmail/api.rb +114 -0
- data/app/connectors/gmail/connector.rb +921 -0
- data/app/connectors/gmail/mime_builder.rb +261 -0
- data/app/connectors/gmail/mime_parser.rb +106 -0
- data/app/connectors/gmail/polling.rb +154 -0
- data/app/connectors/remote_mcp/connector.rb +18 -0
- data/app/connectors/resend/connector.rb +218 -0
- data/app/controllers/concerns/connectors/grant_access.rb +43 -0
- data/app/controllers/connectors/actions_controller.rb +66 -0
- data/app/controllers/connectors/application_controller.rb +5 -0
- data/app/controllers/connectors/credentials_controller.rb +245 -0
- data/app/controllers/connectors/grants_controller.rb +123 -0
- data/app/controllers/connectors/mcp_controller.rb +88 -0
- data/app/controllers/connectors/oauth_controller.rb +134 -0
- data/app/controllers/connectors/types_controller.rb +144 -0
- data/app/controllers/connectors/webhooks_controller.rb +105 -0
- data/app/jobs/connectors/application_job.rb +4 -0
- data/app/jobs/connectors/deliver_webhook_job.rb +27 -0
- data/app/jobs/connectors/poll_job.rb +49 -0
- data/app/models/connectors/application_record.rb +5 -0
- data/app/models/connectors/credential_share.rb +31 -0
- data/app/models/connectors/grant.rb +103 -0
- data/app/models/connectors/mcp_authorization.rb +6 -0
- data/app/models/connectors/mcp_interaction.rb +6 -0
- data/app/models/connectors/poll_state.rb +17 -0
- data/app/models/connectors/webhook_event.rb +19 -0
- data/config/routes.rb +68 -0
- data/db/migrate/20260518210324_create_connectors_grants.rb +49 -0
- data/db/migrate/20260518214609_create_connectors_webhook_events.rb +35 -0
- data/db/migrate/20260521140000_create_connectors_credential_shares.rb +26 -0
- data/db/migrate/20260922120000_create_connectors_poll_states.rb +12 -0
- data/db/migrate/20260922130000_create_connectors_mcp_transactions.rb +18 -0
- data/docs/adding-connectors.md +92 -0
- data/docs/architecture.md +71 -0
- data/docs/releasing.md +60 -0
- data/lib/connectors/action.rb +90 -0
- data/lib/connectors/action_builder.rb +125 -0
- data/lib/connectors/action_runner.rb +99 -0
- data/lib/connectors/auth/scheme/api_key.rb +51 -0
- data/lib/connectors/auth/scheme/oauth2.rb +23 -0
- data/lib/connectors/auth/scheme.rb +35 -0
- data/lib/connectors/auth.rb +4 -0
- data/lib/connectors/auth_injection.rb +65 -0
- data/lib/connectors/client_builder.rb +87 -0
- data/lib/connectors/configuration.rb +138 -0
- data/lib/connectors/connector.rb +565 -0
- data/lib/connectors/credential_schema.rb +219 -0
- data/lib/connectors/credential_tester.rb +85 -0
- data/lib/connectors/credential_type_registry.rb +162 -0
- data/lib/connectors/credential_types/http_auth.rb +171 -0
- data/lib/connectors/engine.rb +123 -0
- data/lib/connectors/errors.rb +88 -0
- data/lib/connectors/grant_policy.rb +13 -0
- data/lib/connectors/mcp/access.rb +50 -0
- data/lib/connectors/mcp/authorization.rb +177 -0
- data/lib/connectors/mcp/authorization_context.rb +25 -0
- data/lib/connectors/mcp/authorization_discovery.rb +42 -0
- data/lib/connectors/mcp/cancellation.rb +36 -0
- data/lib/connectors/mcp/client.rb +137 -0
- data/lib/connectors/mcp/connection_config.rb +48 -0
- data/lib/connectors/mcp/http.rb +108 -0
- data/lib/connectors/mcp/interaction.rb +82 -0
- data/lib/connectors/mcp/pending_transaction.rb +26 -0
- data/lib/connectors/mcp/protocol/2026-07-28.json +3963 -0
- data/lib/connectors/mcp/protocol/LICENSE +216 -0
- data/lib/connectors/mcp/protocol/README.md +8 -0
- data/lib/connectors/mcp/protocol_schema.rb +30 -0
- data/lib/connectors/mcp/schema.rb +45 -0
- data/lib/connectors/mcp/settings.rb +27 -0
- data/lib/connectors/mcp/token_endpoint.rb +48 -0
- data/lib/connectors/mcp/transport.rb +105 -0
- data/lib/connectors/mcp.rb +69 -0
- data/lib/connectors/middleware/authenticate_generic.rb +79 -0
- data/lib/connectors/middleware/auto_refresh.rb +71 -0
- data/lib/connectors/middleware/error_normalization.rb +45 -0
- data/lib/connectors/middleware/grant_status.rb +19 -0
- data/lib/connectors/middleware/pre_authentication.rb +54 -0
- data/lib/connectors/middleware/rate_limit.rb +40 -0
- data/lib/connectors/oauth/authorize_url.rb +78 -0
- data/lib/connectors/oauth/client_authentication.rb +24 -0
- data/lib/connectors/oauth/client_credentials.rb +43 -0
- data/lib/connectors/oauth/grant_writer.rb +73 -0
- data/lib/connectors/oauth/pkce.rb +32 -0
- data/lib/connectors/oauth/revoke.rb +72 -0
- data/lib/connectors/oauth/state.rb +41 -0
- data/lib/connectors/oauth/token_exchange.rb +69 -0
- data/lib/connectors/oauth/token_response.rb +40 -0
- data/lib/connectors/oauth.rb +4 -0
- data/lib/connectors/oauth1.rb +151 -0
- data/lib/connectors/permission_check.rb +33 -0
- data/lib/connectors/poll_runner.rb +50 -0
- data/lib/connectors/pre_authentication_helpers.rb +76 -0
- data/lib/connectors/registry.rb +38 -0
- data/lib/connectors/version.rb +3 -0
- data/lib/connectors/webhook_context.rb +62 -0
- data/lib/connectors/webhook_lifecycle.rb +69 -0
- data/lib/connectors/webhook_methods.rb +48 -0
- data/lib/connectors/webhooks/verifier.rb +31 -0
- data/lib/connectors/webhooks.rb +5 -0
- data/lib/connectors.rb +50 -0
- data/lib/tasks/connectors_mcp.rake +9 -0
- data/lib/tasks/connectors_tasks.rake +4 -0
- data/openapi.yaml +1099 -0
- metadata +263 -0
data/openapi.yaml
ADDED
|
@@ -0,0 +1,1099 @@
|
|
|
1
|
+
openapi: 3.1.0
|
|
2
|
+
info:
|
|
3
|
+
title: Connectors Engine API
|
|
4
|
+
version: "0.1.0"
|
|
5
|
+
description: |
|
|
6
|
+
Rails engine exposing n8n's connections / credentials layer as a host-mountable API.
|
|
7
|
+
Every endpoint is namespaced under the engine's mount path (default `/connectors`).
|
|
8
|
+
|
|
9
|
+
**Auth model.** The engine itself doesn't authenticate requests — the host wires
|
|
10
|
+
`Connectors.configuration.current_owner_resolver` to extract the requester from the
|
|
11
|
+
controller (session, JWT, API key — host's choice). Endpoints that mutate
|
|
12
|
+
credentials require an `Owner` to be resolvable; those that read enforce
|
|
13
|
+
role-based visibility via `principal_resolver` (Phase 9).
|
|
14
|
+
|
|
15
|
+
**Source of truth.** This document is hand-maintained alongside the engine.
|
|
16
|
+
Cross-check against `connectors/config/routes.rb` and the controller files —
|
|
17
|
+
they are the implementation.
|
|
18
|
+
|
|
19
|
+
**Mount path.** The host picks where the engine lives. Reference deployment
|
|
20
|
+
(flow-api) uses `/api/v1/connectors`. The engine introspects its actual
|
|
21
|
+
mount via `Connectors::Engine.mount_path`, so OAuth callback URLs and
|
|
22
|
+
webhook subscribe URLs in responses always reflect reality.
|
|
23
|
+
contact:
|
|
24
|
+
name: Connectors framework
|
|
25
|
+
license:
|
|
26
|
+
name: MIT
|
|
27
|
+
servers:
|
|
28
|
+
- url: "{host}{mount}"
|
|
29
|
+
description: Engine mount in the host app
|
|
30
|
+
variables:
|
|
31
|
+
host:
|
|
32
|
+
default: "http://localhost:3000"
|
|
33
|
+
description: Scheme + host of the host application
|
|
34
|
+
mount:
|
|
35
|
+
default: "/api/v1/connectors"
|
|
36
|
+
description: Path where the host mounts Connectors::Engine
|
|
37
|
+
|
|
38
|
+
tags:
|
|
39
|
+
- name: MCP
|
|
40
|
+
description: External MCP 2026-07-28 tools and authorization
|
|
41
|
+
- name: Catalog
|
|
42
|
+
description: List of registered connector types
|
|
43
|
+
- name: Credentials
|
|
44
|
+
description: CRUD + sharing + revocation
|
|
45
|
+
- name: Grants
|
|
46
|
+
description: "@deprecated alias surface + manual harnesses (test, subscribe, poll)"
|
|
47
|
+
- name: OAuth
|
|
48
|
+
description: OAuth1 + OAuth2 (all grant types) authorize / callback / revoke
|
|
49
|
+
- name: Webhooks
|
|
50
|
+
description: Inbound webhook delivery
|
|
51
|
+
- name: External Secrets
|
|
52
|
+
description: Managed credentials with vault-resolved values
|
|
53
|
+
|
|
54
|
+
paths:
|
|
55
|
+
/credentials/{id}/mcp/tools:
|
|
56
|
+
parameters:
|
|
57
|
+
- { name: id, in: path, required: true, schema: { type: string, format: uuid } }
|
|
58
|
+
get:
|
|
59
|
+
tags: [MCP]
|
|
60
|
+
operationId: listMcpTools
|
|
61
|
+
summary: Discover native MCP tool descriptors for a visible connection
|
|
62
|
+
responses:
|
|
63
|
+
"200":
|
|
64
|
+
description: Complete paginated tool catalog, with original schemas and metadata
|
|
65
|
+
content:
|
|
66
|
+
application/json:
|
|
67
|
+
schema:
|
|
68
|
+
type: object
|
|
69
|
+
required: [tools]
|
|
70
|
+
properties:
|
|
71
|
+
tools: { type: array, items: { type: object, additionalProperties: true } }
|
|
72
|
+
"401": { $ref: "#/components/responses/McpFailure" }
|
|
73
|
+
"403": { $ref: "#/components/responses/McpFailure" }
|
|
74
|
+
"429": { $ref: "#/components/responses/McpRateLimited" }
|
|
75
|
+
"502": { $ref: "#/components/responses/McpFailure" }
|
|
76
|
+
|
|
77
|
+
/credentials/{id}/mcp/tools/call:
|
|
78
|
+
parameters:
|
|
79
|
+
- { name: id, in: path, required: true, schema: { type: string, format: uuid } }
|
|
80
|
+
post:
|
|
81
|
+
tags: [MCP]
|
|
82
|
+
operationId: callMcpTool
|
|
83
|
+
summary: Invoke an MCP tool with editor access
|
|
84
|
+
description: No automatic replay after a timeout or disconnected response. Tool execution errors remain MCP results with isError=true.
|
|
85
|
+
requestBody:
|
|
86
|
+
required: true
|
|
87
|
+
content:
|
|
88
|
+
application/json:
|
|
89
|
+
schema:
|
|
90
|
+
type: object
|
|
91
|
+
required: [name, arguments]
|
|
92
|
+
properties:
|
|
93
|
+
name: { type: string }
|
|
94
|
+
arguments: { type: object, additionalProperties: true }
|
|
95
|
+
responses:
|
|
96
|
+
"200":
|
|
97
|
+
description: Native tool result, or input_required with a durable interaction_id
|
|
98
|
+
content:
|
|
99
|
+
application/json:
|
|
100
|
+
schema: { $ref: "#/components/schemas/McpToolResult" }
|
|
101
|
+
"401": { $ref: "#/components/responses/McpFailure" }
|
|
102
|
+
"403": { $ref: "#/components/responses/McpFailure" }
|
|
103
|
+
"422": { $ref: "#/components/responses/McpFailure" }
|
|
104
|
+
"429": { $ref: "#/components/responses/McpRateLimited" }
|
|
105
|
+
"502": { $ref: "#/components/responses/McpFailure" }
|
|
106
|
+
|
|
107
|
+
/credentials/{id}/mcp/interactions/resume:
|
|
108
|
+
parameters:
|
|
109
|
+
- { name: id, in: path, required: true, schema: { type: string, format: uuid } }
|
|
110
|
+
post:
|
|
111
|
+
tags: [MCP]
|
|
112
|
+
operationId: resumeMcpInteraction
|
|
113
|
+
summary: Resume a pending interaction once as the initiating actor
|
|
114
|
+
requestBody:
|
|
115
|
+
required: true
|
|
116
|
+
content:
|
|
117
|
+
application/json:
|
|
118
|
+
schema:
|
|
119
|
+
type: object
|
|
120
|
+
required: [interaction_id, responses]
|
|
121
|
+
properties:
|
|
122
|
+
interaction_id: { type: string, format: uuid }
|
|
123
|
+
responses:
|
|
124
|
+
type: object
|
|
125
|
+
additionalProperties:
|
|
126
|
+
type: object
|
|
127
|
+
required: [action]
|
|
128
|
+
properties:
|
|
129
|
+
action: { type: string, enum: [accept, decline, cancel] }
|
|
130
|
+
content: { type: object, additionalProperties: true }
|
|
131
|
+
responses:
|
|
132
|
+
"200":
|
|
133
|
+
description: Native completed result or next interaction
|
|
134
|
+
content:
|
|
135
|
+
application/json:
|
|
136
|
+
schema: { $ref: "#/components/schemas/McpToolResult" }
|
|
137
|
+
"401": { $ref: "#/components/responses/McpFailure" }
|
|
138
|
+
"403": { $ref: "#/components/responses/McpFailure" }
|
|
139
|
+
"422": { $ref: "#/components/responses/McpFailure" }
|
|
140
|
+
"429": { $ref: "#/components/responses/McpRateLimited" }
|
|
141
|
+
"502": { $ref: "#/components/responses/McpFailure" }
|
|
142
|
+
|
|
143
|
+
/credentials/{id}/mcp/authorize:
|
|
144
|
+
parameters:
|
|
145
|
+
- { name: id, in: path, required: true, schema: { type: string, format: uuid } }
|
|
146
|
+
post:
|
|
147
|
+
tags: [MCP]
|
|
148
|
+
operationId: authorizeMcpConnection
|
|
149
|
+
summary: Start owner-only OAuth consent or scope upgrade
|
|
150
|
+
requestBody:
|
|
151
|
+
content:
|
|
152
|
+
application/json:
|
|
153
|
+
schema:
|
|
154
|
+
type: object
|
|
155
|
+
properties:
|
|
156
|
+
authorization_context: { type: string, description: Encrypted context returned by a failed MCP operation }
|
|
157
|
+
responses:
|
|
158
|
+
"200":
|
|
159
|
+
description: Browser authorization URL with durable PKCE state
|
|
160
|
+
content:
|
|
161
|
+
application/json:
|
|
162
|
+
schema:
|
|
163
|
+
type: object
|
|
164
|
+
required: [authorization_url]
|
|
165
|
+
properties:
|
|
166
|
+
authorization_url: { type: string, format: uri }
|
|
167
|
+
"403": { $ref: "#/components/responses/McpFailure" }
|
|
168
|
+
"422": { $ref: "#/components/responses/McpFailure" }
|
|
169
|
+
"429": { $ref: "#/components/responses/McpRateLimited" }
|
|
170
|
+
"502": { $ref: "#/components/responses/McpFailure" }
|
|
171
|
+
|
|
172
|
+
/mcp/oauth/callback:
|
|
173
|
+
get:
|
|
174
|
+
tags: [MCP]
|
|
175
|
+
operationId: completeMcpAuthorizationRedirect
|
|
176
|
+
summary: Complete OAuth as the authenticated initiating owner
|
|
177
|
+
parameters:
|
|
178
|
+
- { name: state, in: query, required: true, schema: { type: string } }
|
|
179
|
+
- { name: code, in: query, schema: { type: string } }
|
|
180
|
+
- { name: iss, in: query, schema: { type: string } }
|
|
181
|
+
- { name: error, in: query, schema: { type: string } }
|
|
182
|
+
responses:
|
|
183
|
+
"200": { description: Authorization completed }
|
|
184
|
+
"403": { $ref: "#/components/responses/McpFailure" }
|
|
185
|
+
"404": { $ref: "#/components/responses/NotFound" }
|
|
186
|
+
"429": { $ref: "#/components/responses/McpRateLimited" }
|
|
187
|
+
"502": { $ref: "#/components/responses/McpFailure" }
|
|
188
|
+
post:
|
|
189
|
+
tags: [MCP]
|
|
190
|
+
operationId: completeMcpAuthorizationExchange
|
|
191
|
+
summary: Complete OAuth from a frontend callback
|
|
192
|
+
requestBody:
|
|
193
|
+
required: true
|
|
194
|
+
content:
|
|
195
|
+
application/json:
|
|
196
|
+
schema:
|
|
197
|
+
type: object
|
|
198
|
+
required: [state]
|
|
199
|
+
properties:
|
|
200
|
+
state: { type: string }
|
|
201
|
+
code: { type: string }
|
|
202
|
+
iss: { type: string }
|
|
203
|
+
error: { type: string }
|
|
204
|
+
responses:
|
|
205
|
+
"200": { description: Authorization completed }
|
|
206
|
+
"403": { $ref: "#/components/responses/McpFailure" }
|
|
207
|
+
"404": { $ref: "#/components/responses/NotFound" }
|
|
208
|
+
"429": { $ref: "#/components/responses/McpRateLimited" }
|
|
209
|
+
"502": { $ref: "#/components/responses/McpFailure" }
|
|
210
|
+
|
|
211
|
+
# =========================================================================
|
|
212
|
+
# CATALOG
|
|
213
|
+
# =========================================================================
|
|
214
|
+
/types:
|
|
215
|
+
get:
|
|
216
|
+
tags: [Catalog]
|
|
217
|
+
summary: List every registered connector type
|
|
218
|
+
operationId: listTypes
|
|
219
|
+
responses:
|
|
220
|
+
"200":
|
|
221
|
+
description: Catalog
|
|
222
|
+
content:
|
|
223
|
+
application/json:
|
|
224
|
+
schema:
|
|
225
|
+
type: object
|
|
226
|
+
properties:
|
|
227
|
+
types:
|
|
228
|
+
type: array
|
|
229
|
+
items: { $ref: "#/components/schemas/CredentialType" }
|
|
230
|
+
|
|
231
|
+
/types/{name}:
|
|
232
|
+
get:
|
|
233
|
+
tags: [Catalog]
|
|
234
|
+
summary: Full description of one connector type
|
|
235
|
+
operationId: getType
|
|
236
|
+
parameters:
|
|
237
|
+
- { name: name, in: path, required: true, schema: { type: string } }
|
|
238
|
+
responses:
|
|
239
|
+
"200":
|
|
240
|
+
description: Single type
|
|
241
|
+
content:
|
|
242
|
+
application/json:
|
|
243
|
+
schema: { $ref: "#/components/schemas/CredentialType" }
|
|
244
|
+
"404": { $ref: "#/components/responses/NotFound" }
|
|
245
|
+
|
|
246
|
+
# =========================================================================
|
|
247
|
+
# CREDENTIALS CRUD
|
|
248
|
+
# =========================================================================
|
|
249
|
+
/credentials:
|
|
250
|
+
get:
|
|
251
|
+
tags: [Credentials]
|
|
252
|
+
summary: List credentials visible to the requester (owned + shared)
|
|
253
|
+
operationId: listCredentials
|
|
254
|
+
parameters:
|
|
255
|
+
- { name: type, in: query, schema: { type: string } }
|
|
256
|
+
- { name: include_data, in: query, description: "Owner-only decrypted data; MCP returns public configuration for all visible connections", schema: { type: boolean, default: false } }
|
|
257
|
+
responses:
|
|
258
|
+
"200":
|
|
259
|
+
description: Visible credentials
|
|
260
|
+
content:
|
|
261
|
+
application/json:
|
|
262
|
+
schema:
|
|
263
|
+
type: object
|
|
264
|
+
properties:
|
|
265
|
+
credentials:
|
|
266
|
+
type: array
|
|
267
|
+
items: { $ref: "#/components/schemas/Credential" }
|
|
268
|
+
"401": { $ref: "#/components/responses/Unauthorized" }
|
|
269
|
+
post:
|
|
270
|
+
tags: [Credentials]
|
|
271
|
+
summary: Create a credential (paste-the-key flow)
|
|
272
|
+
operationId: createCredential
|
|
273
|
+
requestBody:
|
|
274
|
+
required: true
|
|
275
|
+
content:
|
|
276
|
+
application/json:
|
|
277
|
+
schema:
|
|
278
|
+
type: object
|
|
279
|
+
required: [type]
|
|
280
|
+
properties:
|
|
281
|
+
type: { type: string, description: "connector key" }
|
|
282
|
+
name: { type: string }
|
|
283
|
+
data: { type: object, additionalProperties: true, description: "credential values" }
|
|
284
|
+
external_ref: { type: string, description: "vault reference (Phase 10)" }
|
|
285
|
+
is_managed: { type: boolean, default: false }
|
|
286
|
+
responses:
|
|
287
|
+
"201":
|
|
288
|
+
description: Created
|
|
289
|
+
content: { application/json: { schema: { $ref: "#/components/schemas/Credential" } } }
|
|
290
|
+
"401": { $ref: "#/components/responses/Unauthorized" }
|
|
291
|
+
"404": { $ref: "#/components/responses/NotFound" }
|
|
292
|
+
|
|
293
|
+
/credentials/for-workflow:
|
|
294
|
+
get:
|
|
295
|
+
tags: [Credentials]
|
|
296
|
+
summary: List credentials available to a workflow editor
|
|
297
|
+
operationId: listCredentialsForWorkflow
|
|
298
|
+
parameters:
|
|
299
|
+
- { name: type, in: query, schema: { type: string } }
|
|
300
|
+
responses:
|
|
301
|
+
"200":
|
|
302
|
+
description: Visible credentials
|
|
303
|
+
content:
|
|
304
|
+
application/json:
|
|
305
|
+
schema:
|
|
306
|
+
type: object
|
|
307
|
+
properties:
|
|
308
|
+
credentials:
|
|
309
|
+
type: array
|
|
310
|
+
items: { $ref: "#/components/schemas/Credential" }
|
|
311
|
+
|
|
312
|
+
/credentials/new:
|
|
313
|
+
get:
|
|
314
|
+
tags: [Credentials]
|
|
315
|
+
summary: Server-generated unique default name ("Resend account 3")
|
|
316
|
+
operationId: newCredentialName
|
|
317
|
+
parameters:
|
|
318
|
+
- { name: type, in: query, required: true, schema: { type: string } }
|
|
319
|
+
responses:
|
|
320
|
+
"200":
|
|
321
|
+
description: Suggested name
|
|
322
|
+
content:
|
|
323
|
+
application/json:
|
|
324
|
+
schema:
|
|
325
|
+
type: object
|
|
326
|
+
properties: { name: { type: string } }
|
|
327
|
+
"404": { $ref: "#/components/responses/NotFound" }
|
|
328
|
+
|
|
329
|
+
/credentials/test:
|
|
330
|
+
post:
|
|
331
|
+
tags: [Credentials]
|
|
332
|
+
summary: Test an unsaved credential
|
|
333
|
+
operationId: testUnsavedCredential
|
|
334
|
+
requestBody:
|
|
335
|
+
required: true
|
|
336
|
+
content:
|
|
337
|
+
application/json:
|
|
338
|
+
schema:
|
|
339
|
+
type: object
|
|
340
|
+
required: [type]
|
|
341
|
+
properties:
|
|
342
|
+
type: { type: string }
|
|
343
|
+
data: { type: object, additionalProperties: true }
|
|
344
|
+
responses:
|
|
345
|
+
"200":
|
|
346
|
+
description: Test passed
|
|
347
|
+
content: { application/json: { schema: { $ref: "#/components/schemas/TestResult" } } }
|
|
348
|
+
"422":
|
|
349
|
+
description: Test failed (provider rejected)
|
|
350
|
+
content: { application/json: { schema: { $ref: "#/components/schemas/TestResult" } } }
|
|
351
|
+
|
|
352
|
+
/credentials/{id}:
|
|
353
|
+
parameters:
|
|
354
|
+
- { name: id, in: path, required: true, schema: { type: string, format: uuid } }
|
|
355
|
+
get:
|
|
356
|
+
tags: [Credentials]
|
|
357
|
+
summary: Show one credential (viewer-or-better)
|
|
358
|
+
operationId: getCredential
|
|
359
|
+
parameters:
|
|
360
|
+
- { name: include_data, in: query, description: "Owner-only decrypted data; MCP returns public configuration for all visible connections", schema: { type: boolean, default: false } }
|
|
361
|
+
responses:
|
|
362
|
+
"200":
|
|
363
|
+
description: Credential
|
|
364
|
+
content: { application/json: { schema: { $ref: "#/components/schemas/Credential" } } }
|
|
365
|
+
"404": { $ref: "#/components/responses/NotFound" }
|
|
366
|
+
patch:
|
|
367
|
+
tags: [Credentials]
|
|
368
|
+
summary: Update a credential (editor-or-owner)
|
|
369
|
+
operationId: updateCredential
|
|
370
|
+
requestBody:
|
|
371
|
+
required: true
|
|
372
|
+
content:
|
|
373
|
+
application/json:
|
|
374
|
+
schema:
|
|
375
|
+
type: object
|
|
376
|
+
properties:
|
|
377
|
+
name: { type: string }
|
|
378
|
+
data: { type: object, additionalProperties: true }
|
|
379
|
+
responses:
|
|
380
|
+
"200":
|
|
381
|
+
description: Updated
|
|
382
|
+
content: { application/json: { schema: { $ref: "#/components/schemas/Credential" } } }
|
|
383
|
+
"401": { $ref: "#/components/responses/Unauthorized" }
|
|
384
|
+
put:
|
|
385
|
+
tags: [Credentials]
|
|
386
|
+
summary: Alias for PATCH (back-compat)
|
|
387
|
+
operationId: replaceCredential
|
|
388
|
+
requestBody:
|
|
389
|
+
required: true
|
|
390
|
+
content:
|
|
391
|
+
application/json:
|
|
392
|
+
schema:
|
|
393
|
+
type: object
|
|
394
|
+
properties:
|
|
395
|
+
name: { type: string }
|
|
396
|
+
data: { type: object, additionalProperties: true }
|
|
397
|
+
responses:
|
|
398
|
+
"200":
|
|
399
|
+
description: Updated
|
|
400
|
+
content: { application/json: { schema: { $ref: "#/components/schemas/Credential" } } }
|
|
401
|
+
delete:
|
|
402
|
+
tags: [Credentials]
|
|
403
|
+
summary: Delete a credential (owner only)
|
|
404
|
+
operationId: deleteCredential
|
|
405
|
+
responses:
|
|
406
|
+
"204": { description: Deleted }
|
|
407
|
+
"401": { $ref: "#/components/responses/Unauthorized" }
|
|
408
|
+
|
|
409
|
+
# =========================================================================
|
|
410
|
+
# ACTIONS — what a credential can DO
|
|
411
|
+
# =========================================================================
|
|
412
|
+
/credentials/{id}/actions:
|
|
413
|
+
parameters:
|
|
414
|
+
- { name: id, in: path, required: true, schema: { type: string, format: uuid } }
|
|
415
|
+
get:
|
|
416
|
+
tags: [Actions]
|
|
417
|
+
summary: List actions available on this credential's connector
|
|
418
|
+
operationId: listCredentialActions
|
|
419
|
+
responses:
|
|
420
|
+
"200":
|
|
421
|
+
description: Actions
|
|
422
|
+
content:
|
|
423
|
+
application/json:
|
|
424
|
+
schema:
|
|
425
|
+
type: object
|
|
426
|
+
properties:
|
|
427
|
+
actions:
|
|
428
|
+
type: array
|
|
429
|
+
items: { $ref: "#/components/schemas/Action" }
|
|
430
|
+
"404": { $ref: "#/components/responses/NotFound" }
|
|
431
|
+
|
|
432
|
+
/credentials/{id}/actions/{name}:
|
|
433
|
+
parameters:
|
|
434
|
+
- { name: id, in: path, required: true, schema: { type: string, format: uuid } }
|
|
435
|
+
- { name: name, in: path, required: true, schema: { type: string } }
|
|
436
|
+
post:
|
|
437
|
+
tags: [Actions]
|
|
438
|
+
summary: Invoke a connector action with this credential
|
|
439
|
+
description: |
|
|
440
|
+
Validates `data` against the action's param schema, then runs the
|
|
441
|
+
action's execute block in the connector instance's context. Returns
|
|
442
|
+
a normalized envelope — `status: "ok"` with `data`, or `status: "error"`
|
|
443
|
+
with a typed `error` object (`invalid_params`, `authentication_failed`,
|
|
444
|
+
`forbidden`, `rate_limited`, `api_error`).
|
|
445
|
+
operationId: invokeCredentialAction
|
|
446
|
+
requestBody:
|
|
447
|
+
required: true
|
|
448
|
+
content:
|
|
449
|
+
application/json:
|
|
450
|
+
schema:
|
|
451
|
+
type: object
|
|
452
|
+
properties:
|
|
453
|
+
data: { type: object, additionalProperties: true, description: "action input params" }
|
|
454
|
+
responses:
|
|
455
|
+
"200":
|
|
456
|
+
description: Action succeeded
|
|
457
|
+
content:
|
|
458
|
+
application/json:
|
|
459
|
+
schema: { $ref: "#/components/schemas/ActionResult" }
|
|
460
|
+
"401": { $ref: "#/components/responses/Unauthorized" }
|
|
461
|
+
"403":
|
|
462
|
+
description: Provider permission denied
|
|
463
|
+
content:
|
|
464
|
+
application/json:
|
|
465
|
+
schema: { $ref: "#/components/schemas/ActionResult" }
|
|
466
|
+
"404": { $ref: "#/components/responses/NotFound" }
|
|
467
|
+
"422":
|
|
468
|
+
description: Invalid params
|
|
469
|
+
content:
|
|
470
|
+
application/json:
|
|
471
|
+
schema: { $ref: "#/components/schemas/ActionResult" }
|
|
472
|
+
"429":
|
|
473
|
+
description: Provider rate-limited the request
|
|
474
|
+
content:
|
|
475
|
+
application/json:
|
|
476
|
+
schema: { $ref: "#/components/schemas/ActionResult" }
|
|
477
|
+
"502":
|
|
478
|
+
description: Provider returned an error
|
|
479
|
+
content:
|
|
480
|
+
application/json:
|
|
481
|
+
schema: { $ref: "#/components/schemas/ActionResult" }
|
|
482
|
+
|
|
483
|
+
/credentials/{id}/revoke:
|
|
484
|
+
parameters:
|
|
485
|
+
- { name: id, in: path, required: true, schema: { type: string, format: uuid } }
|
|
486
|
+
post:
|
|
487
|
+
tags: [Credentials, OAuth]
|
|
488
|
+
summary: RFC 7009 token revocation
|
|
489
|
+
operationId: revokeCredential
|
|
490
|
+
responses:
|
|
491
|
+
"200":
|
|
492
|
+
description: Revoked
|
|
493
|
+
content:
|
|
494
|
+
application/json:
|
|
495
|
+
schema:
|
|
496
|
+
type: object
|
|
497
|
+
properties:
|
|
498
|
+
grant_id: { type: string, format: uuid }
|
|
499
|
+
status: { type: string, example: "revoked" }
|
|
500
|
+
"401": { $ref: "#/components/responses/Unauthorized" }
|
|
501
|
+
|
|
502
|
+
/credentials/{id}/share:
|
|
503
|
+
parameters:
|
|
504
|
+
- { name: id, in: path, required: true, schema: { type: string, format: uuid } }
|
|
505
|
+
put:
|
|
506
|
+
tags: [Credentials]
|
|
507
|
+
summary: Share a credential with a principal (owner only, idempotent)
|
|
508
|
+
operationId: shareCredential
|
|
509
|
+
requestBody:
|
|
510
|
+
required: true
|
|
511
|
+
content:
|
|
512
|
+
application/json:
|
|
513
|
+
schema: { $ref: "#/components/schemas/SharePayload" }
|
|
514
|
+
responses:
|
|
515
|
+
"200":
|
|
516
|
+
description: Share record
|
|
517
|
+
content: { application/json: { schema: { $ref: "#/components/schemas/CredentialShare" } } }
|
|
518
|
+
"401": { $ref: "#/components/responses/Unauthorized" }
|
|
519
|
+
delete:
|
|
520
|
+
tags: [Credentials]
|
|
521
|
+
summary: Revoke a share
|
|
522
|
+
operationId: unshareCredential
|
|
523
|
+
requestBody:
|
|
524
|
+
required: true
|
|
525
|
+
content:
|
|
526
|
+
application/json:
|
|
527
|
+
schema:
|
|
528
|
+
type: object
|
|
529
|
+
required: [principal_type, principal_id]
|
|
530
|
+
properties:
|
|
531
|
+
principal_type: { type: string }
|
|
532
|
+
principal_id: { type: string, format: uuid }
|
|
533
|
+
responses:
|
|
534
|
+
"204": { description: Unshared }
|
|
535
|
+
"401": { $ref: "#/components/responses/Unauthorized" }
|
|
536
|
+
"404": { $ref: "#/components/responses/NotFound" }
|
|
537
|
+
|
|
538
|
+
/credentials/{id}/transfer:
|
|
539
|
+
parameters:
|
|
540
|
+
- { name: id, in: path, required: true, schema: { type: string, format: uuid } }
|
|
541
|
+
put:
|
|
542
|
+
tags: [Credentials]
|
|
543
|
+
summary: Transfer ownership to a different owner (owner only)
|
|
544
|
+
operationId: transferCredential
|
|
545
|
+
requestBody:
|
|
546
|
+
required: true
|
|
547
|
+
content:
|
|
548
|
+
application/json:
|
|
549
|
+
schema:
|
|
550
|
+
type: object
|
|
551
|
+
required: [owner_id]
|
|
552
|
+
properties: { owner_id: { type: string, format: uuid } }
|
|
553
|
+
responses:
|
|
554
|
+
"200":
|
|
555
|
+
description: Reassigned
|
|
556
|
+
content: { application/json: { schema: { $ref: "#/components/schemas/Credential" } } }
|
|
557
|
+
"401": { $ref: "#/components/responses/Unauthorized" }
|
|
558
|
+
|
|
559
|
+
# =========================================================================
|
|
560
|
+
# GRANTS — manual harnesses
|
|
561
|
+
# =========================================================================
|
|
562
|
+
/grants:
|
|
563
|
+
get:
|
|
564
|
+
tags: [Grants]
|
|
565
|
+
summary: "@deprecated alias for /credentials index"
|
|
566
|
+
operationId: listGrants
|
|
567
|
+
parameters:
|
|
568
|
+
- { name: connector_key, in: query, schema: { type: string } }
|
|
569
|
+
responses:
|
|
570
|
+
"200":
|
|
571
|
+
description: Grants
|
|
572
|
+
content:
|
|
573
|
+
application/json:
|
|
574
|
+
schema:
|
|
575
|
+
type: object
|
|
576
|
+
properties:
|
|
577
|
+
grants:
|
|
578
|
+
type: array
|
|
579
|
+
items: { $ref: "#/components/schemas/Credential" }
|
|
580
|
+
|
|
581
|
+
/grants/{id}/test:
|
|
582
|
+
parameters:
|
|
583
|
+
- { name: id, in: path, required: true, schema: { type: string, format: uuid } }
|
|
584
|
+
post:
|
|
585
|
+
tags: [Grants]
|
|
586
|
+
summary: Run the connector's declared test_request against the live provider
|
|
587
|
+
operationId: testGrant
|
|
588
|
+
responses:
|
|
589
|
+
"200":
|
|
590
|
+
description: Test passed
|
|
591
|
+
content: { application/json: { schema: { $ref: "#/components/schemas/TestResult" } } }
|
|
592
|
+
"422":
|
|
593
|
+
description: Test failed
|
|
594
|
+
content: { application/json: { schema: { $ref: "#/components/schemas/TestResult" } } }
|
|
595
|
+
|
|
596
|
+
/grants/{id}/webhook_subscribe:
|
|
597
|
+
parameters:
|
|
598
|
+
- { name: id, in: path, required: true, schema: { type: string, format: uuid } }
|
|
599
|
+
post:
|
|
600
|
+
tags: [Grants, Webhooks]
|
|
601
|
+
summary: Run the connector's webhook_methods subscribe lifecycle
|
|
602
|
+
operationId: subscribeWebhook
|
|
603
|
+
requestBody:
|
|
604
|
+
required: false
|
|
605
|
+
content:
|
|
606
|
+
application/json:
|
|
607
|
+
schema:
|
|
608
|
+
type: object
|
|
609
|
+
properties:
|
|
610
|
+
webhook_name: { type: string, default: "default" }
|
|
611
|
+
hook_url: { type: string, format: uri }
|
|
612
|
+
responses:
|
|
613
|
+
"200":
|
|
614
|
+
description: Subscribed or already-exists
|
|
615
|
+
content:
|
|
616
|
+
application/json:
|
|
617
|
+
schema:
|
|
618
|
+
type: object
|
|
619
|
+
properties:
|
|
620
|
+
status: { type: string, enum: [created, exists] }
|
|
621
|
+
webhook_name: { type: string }
|
|
622
|
+
hook_url: { type: string }
|
|
623
|
+
static_data: { type: object, additionalProperties: true }
|
|
624
|
+
delete:
|
|
625
|
+
tags: [Grants, Webhooks]
|
|
626
|
+
summary: Unsubscribe — run the delete callback
|
|
627
|
+
operationId: unsubscribeWebhook
|
|
628
|
+
requestBody:
|
|
629
|
+
required: false
|
|
630
|
+
content:
|
|
631
|
+
application/json:
|
|
632
|
+
schema:
|
|
633
|
+
type: object
|
|
634
|
+
properties: { webhook_name: { type: string, default: "default" } }
|
|
635
|
+
responses:
|
|
636
|
+
"200":
|
|
637
|
+
description: Deleted
|
|
638
|
+
content:
|
|
639
|
+
application/json:
|
|
640
|
+
schema:
|
|
641
|
+
type: object
|
|
642
|
+
properties:
|
|
643
|
+
status: { type: string, example: "deleted" }
|
|
644
|
+
webhook_name: { type: string }
|
|
645
|
+
static_data: { type: object, additionalProperties: true }
|
|
646
|
+
|
|
647
|
+
/grants/{id}/poll:
|
|
648
|
+
parameters:
|
|
649
|
+
- { name: id, in: path, required: true, schema: { type: string, format: uuid } }
|
|
650
|
+
post:
|
|
651
|
+
tags: [Grants]
|
|
652
|
+
summary: Fire the polling block once
|
|
653
|
+
operationId: pollGrant
|
|
654
|
+
requestBody:
|
|
655
|
+
required: false
|
|
656
|
+
content:
|
|
657
|
+
application/json:
|
|
658
|
+
schema:
|
|
659
|
+
type: object
|
|
660
|
+
properties:
|
|
661
|
+
instance_key:
|
|
662
|
+
type: string
|
|
663
|
+
minLength: 1
|
|
664
|
+
description: Stable consumer identifier; isolates cursor and filter state. Omit for the legacy per-grant cursor.
|
|
665
|
+
responses:
|
|
666
|
+
"400":
|
|
667
|
+
description: Invalid instance key
|
|
668
|
+
"404": { $ref: "#/components/responses/NotFound" }
|
|
669
|
+
"200":
|
|
670
|
+
description: Items + new cursor
|
|
671
|
+
content:
|
|
672
|
+
application/json:
|
|
673
|
+
schema:
|
|
674
|
+
type: object
|
|
675
|
+
properties:
|
|
676
|
+
items: { type: array, items: { type: object, additionalProperties: true } }
|
|
677
|
+
static_data: { type: object, additionalProperties: true }
|
|
678
|
+
|
|
679
|
+
# =========================================================================
|
|
680
|
+
# OAUTH
|
|
681
|
+
# =========================================================================
|
|
682
|
+
/{connector_key}/authorize:
|
|
683
|
+
parameters:
|
|
684
|
+
- { name: connector_key, in: path, required: true, schema: { type: string } }
|
|
685
|
+
get:
|
|
686
|
+
tags: [OAuth]
|
|
687
|
+
summary: Start OAuth authorize flow
|
|
688
|
+
operationId: oauthAuthorize
|
|
689
|
+
description: |
|
|
690
|
+
Creates a new connection unless grant_id selects an owned connection to reconnect.
|
|
691
|
+
Reconnection must retain the provider and known account identity.
|
|
692
|
+
Dispatches by connector configuration:
|
|
693
|
+
- `oauth2 grant_type: "authorizationCode"|"pkce"` → 302 to provider authorize URL
|
|
694
|
+
- `oauth2 grant_type: "clientCredentials"` → exchange in-place, returns grant JSON
|
|
695
|
+
- `oauth1` → request-token leg, then 302
|
|
696
|
+
parameters:
|
|
697
|
+
- { name: grant_id, in: query, schema: { type: string, format: uuid }, description: "Reconnect this owned connection instead of creating a new one." }
|
|
698
|
+
- { name: return_to, in: query, schema: { type: string }, description: "URL to redirect to after callback completes" }
|
|
699
|
+
- { name: scope, in: query, schema: { type: string }, description: "Override the connector's declared default scope. The connector SUGGESTS scopes; the host decides." }
|
|
700
|
+
responses:
|
|
701
|
+
"302":
|
|
702
|
+
description: Redirect to provider (or to return_to after callback)
|
|
703
|
+
headers:
|
|
704
|
+
Location: { schema: { type: string } }
|
|
705
|
+
"200":
|
|
706
|
+
description: clientCredentials grant created in-place
|
|
707
|
+
content:
|
|
708
|
+
application/json:
|
|
709
|
+
schema:
|
|
710
|
+
type: object
|
|
711
|
+
properties:
|
|
712
|
+
grant_id: { type: string, format: uuid }
|
|
713
|
+
connector_key: { type: string }
|
|
714
|
+
status: { type: string, example: "active" }
|
|
715
|
+
"401": { $ref: "#/components/responses/Unauthorized" }
|
|
716
|
+
"404": { $ref: "#/components/responses/NotFound" }
|
|
717
|
+
|
|
718
|
+
/{connector_key}/authorize.json:
|
|
719
|
+
parameters:
|
|
720
|
+
- { name: connector_key, in: path, required: true, schema: { type: string } }
|
|
721
|
+
get:
|
|
722
|
+
tags: [OAuth]
|
|
723
|
+
summary: Return the authorize URL as JSON for popup-based flows
|
|
724
|
+
operationId: oauthAuthorizeJson
|
|
725
|
+
description: Creates a new connection unless grant_id explicitly selects an owned connection to reconnect.
|
|
726
|
+
parameters:
|
|
727
|
+
- { name: grant_id, in: query, schema: { type: string, format: uuid }, description: "Reconnect this owned connection instead of creating a new one." }
|
|
728
|
+
- { name: return_to, in: query, schema: { type: string } }
|
|
729
|
+
- { name: scope, in: query, schema: { type: string }, description: "Override the connector's declared default scope (see /authorize for details)." }
|
|
730
|
+
responses:
|
|
731
|
+
"200":
|
|
732
|
+
description: Authorize URL
|
|
733
|
+
content:
|
|
734
|
+
application/json:
|
|
735
|
+
schema:
|
|
736
|
+
type: object
|
|
737
|
+
properties:
|
|
738
|
+
authorize_url: { type: string, format: uri }
|
|
739
|
+
connector_key: { type: string }
|
|
740
|
+
|
|
741
|
+
/{connector_key}/callback:
|
|
742
|
+
parameters:
|
|
743
|
+
- { name: connector_key, in: path, required: true, schema: { type: string } }
|
|
744
|
+
get:
|
|
745
|
+
tags: [OAuth]
|
|
746
|
+
summary: OAuth callback (OAuth2 + OAuth1)
|
|
747
|
+
operationId: oauthCallback
|
|
748
|
+
description: |
|
|
749
|
+
Accepts EITHER OAuth2 callback (`?code=&state=`) OR OAuth1 callback
|
|
750
|
+
(`?oauth_token=&oauth_verifier=&state=`). Validates encrypted state, exchanges
|
|
751
|
+
for tokens, creates a Grant or reconnects the explicitly selected Grant, and either redirects to `state.return_to` or returns the grant JSON.
|
|
752
|
+
parameters:
|
|
753
|
+
- { name: code, in: query, schema: { type: string } }
|
|
754
|
+
- { name: state, in: query, required: true, schema: { type: string } }
|
|
755
|
+
- { name: oauth_token, in: query, schema: { type: string } }
|
|
756
|
+
- { name: oauth_verifier, in: query, schema: { type: string } }
|
|
757
|
+
responses:
|
|
758
|
+
"302":
|
|
759
|
+
description: Redirect to state.return_to
|
|
760
|
+
headers: { Location: { schema: { type: string } } }
|
|
761
|
+
"200":
|
|
762
|
+
description: Grant JSON
|
|
763
|
+
content:
|
|
764
|
+
application/json:
|
|
765
|
+
schema:
|
|
766
|
+
type: object
|
|
767
|
+
properties:
|
|
768
|
+
grant_id: { type: string, format: uuid }
|
|
769
|
+
connector_key: { type: string }
|
|
770
|
+
status: { type: string }
|
|
771
|
+
"401":
|
|
772
|
+
description: Invalid state or token exchange failed
|
|
773
|
+
content: { application/json: { schema: { $ref: "#/components/schemas/Error" } } }
|
|
774
|
+
"404":
|
|
775
|
+
description: Owner not found
|
|
776
|
+
content: { application/json: { schema: { $ref: "#/components/schemas/Error" } } }
|
|
777
|
+
|
|
778
|
+
# =========================================================================
|
|
779
|
+
# WEBHOOKS (inbound)
|
|
780
|
+
# =========================================================================
|
|
781
|
+
/{connector_key}/webhook:
|
|
782
|
+
parameters:
|
|
783
|
+
- { name: connector_key, in: path, required: true, schema: { type: string } }
|
|
784
|
+
post:
|
|
785
|
+
tags: [Webhooks]
|
|
786
|
+
summary: App-level webhook (single URL per app; grant resolved from payload)
|
|
787
|
+
operationId: receiveAppWebhook
|
|
788
|
+
requestBody:
|
|
789
|
+
required: true
|
|
790
|
+
content:
|
|
791
|
+
application/json: { schema: { type: object, additionalProperties: true } }
|
|
792
|
+
application/x-www-form-urlencoded: { schema: { type: object, additionalProperties: true } }
|
|
793
|
+
responses:
|
|
794
|
+
"202": { $ref: "#/components/responses/WebhookAccepted" }
|
|
795
|
+
"200":
|
|
796
|
+
description: URL-verification challenge response
|
|
797
|
+
content: { application/json: { schema: { type: object, additionalProperties: true } } }
|
|
798
|
+
"401": { $ref: "#/components/responses/Unauthorized" }
|
|
799
|
+
"404": { $ref: "#/components/responses/NotFound" }
|
|
800
|
+
|
|
801
|
+
/{connector_key}/webhook/{webhook_name}:
|
|
802
|
+
parameters:
|
|
803
|
+
- { name: connector_key, in: path, required: true, schema: { type: string } }
|
|
804
|
+
- { name: webhook_name, in: path, required: true, schema: { type: string } }
|
|
805
|
+
post:
|
|
806
|
+
tags: [Webhooks]
|
|
807
|
+
summary: App-level named-group webhook (Phase 7)
|
|
808
|
+
operationId: receiveAppWebhookNamed
|
|
809
|
+
requestBody:
|
|
810
|
+
required: true
|
|
811
|
+
content:
|
|
812
|
+
application/json: { schema: { type: object, additionalProperties: true } }
|
|
813
|
+
responses:
|
|
814
|
+
"202": { $ref: "#/components/responses/WebhookAccepted" }
|
|
815
|
+
"200":
|
|
816
|
+
description: URL-verification challenge response
|
|
817
|
+
content: { application/json: { schema: { type: object, additionalProperties: true } } }
|
|
818
|
+
|
|
819
|
+
/{connector_key}/{grant_id}/webhook:
|
|
820
|
+
parameters:
|
|
821
|
+
- { name: connector_key, in: path, required: true, schema: { type: string } }
|
|
822
|
+
- { name: grant_id, in: path, required: true, schema: { type: string, format: uuid } }
|
|
823
|
+
post:
|
|
824
|
+
tags: [Webhooks]
|
|
825
|
+
summary: Per-grant webhook (grant id in URL)
|
|
826
|
+
operationId: receiveGrantWebhook
|
|
827
|
+
requestBody:
|
|
828
|
+
required: true
|
|
829
|
+
content:
|
|
830
|
+
application/json: { schema: { type: object, additionalProperties: true } }
|
|
831
|
+
responses:
|
|
832
|
+
"202": { $ref: "#/components/responses/WebhookAccepted" }
|
|
833
|
+
|
|
834
|
+
/{connector_key}/{grant_id}/webhook/{webhook_name}:
|
|
835
|
+
parameters:
|
|
836
|
+
- { name: connector_key, in: path, required: true, schema: { type: string } }
|
|
837
|
+
- { name: grant_id, in: path, required: true, schema: { type: string, format: uuid } }
|
|
838
|
+
- { name: webhook_name, in: path, required: true, schema: { type: string } }
|
|
839
|
+
post:
|
|
840
|
+
tags: [Webhooks]
|
|
841
|
+
summary: Per-grant named-group webhook
|
|
842
|
+
operationId: receiveGrantWebhookNamed
|
|
843
|
+
requestBody:
|
|
844
|
+
required: true
|
|
845
|
+
content:
|
|
846
|
+
application/json: { schema: { type: object, additionalProperties: true } }
|
|
847
|
+
responses:
|
|
848
|
+
"202": { $ref: "#/components/responses/WebhookAccepted" }
|
|
849
|
+
|
|
850
|
+
components:
|
|
851
|
+
schemas:
|
|
852
|
+
McpToolResult:
|
|
853
|
+
type: object
|
|
854
|
+
additionalProperties: true
|
|
855
|
+
properties:
|
|
856
|
+
resultType: { type: string, enum: [complete, input_required] }
|
|
857
|
+
content: { type: array, items: { type: object, additionalProperties: true } }
|
|
858
|
+
structuredContent: {}
|
|
859
|
+
isError: { type: boolean }
|
|
860
|
+
interaction_id: { type: string, format: uuid }
|
|
861
|
+
inputRequests: { type: object, additionalProperties: true }
|
|
862
|
+
McpError:
|
|
863
|
+
type: object
|
|
864
|
+
required: [error]
|
|
865
|
+
properties:
|
|
866
|
+
error:
|
|
867
|
+
type: object
|
|
868
|
+
required: [type, message]
|
|
869
|
+
properties:
|
|
870
|
+
type: { type: string }
|
|
871
|
+
message: { type: string }
|
|
872
|
+
retry_after: { type: string, description: "rate_limited only; valid upstream delay-seconds or HTTP date, omitted if unavailable" }
|
|
873
|
+
authorization_context:
|
|
874
|
+
type: string
|
|
875
|
+
description: Encrypted owner consent context; pass to the authorize endpoint for scope upgrades.
|
|
876
|
+
CredentialType:
|
|
877
|
+
type: object
|
|
878
|
+
properties:
|
|
879
|
+
name: { type: string, description: "machine key" }
|
|
880
|
+
display_name: { type: string }
|
|
881
|
+
key: { type: string, deprecated: true, description: "@deprecated — use name" }
|
|
882
|
+
label: { type: string, deprecated: true, description: "@deprecated — use display_name" }
|
|
883
|
+
icon: { type: string, nullable: true }
|
|
884
|
+
icon_color: { type: string, nullable: true }
|
|
885
|
+
documentation_url: { type: string, nullable: true }
|
|
886
|
+
llm_docs: { type: string, nullable: true, description: "provider's llms.txt / llms-full.txt URL (llmstxt.org)" }
|
|
887
|
+
instructions: { type: string, nullable: true, description: "markdown rendered at the top of the Add Connection dialog (e.g. how to generate an API key); nil when no setup guidance is needed" }
|
|
888
|
+
extends: { type: array, items: { type: string }, description: "base credential types inherited from" }
|
|
889
|
+
properties:
|
|
890
|
+
type: array
|
|
891
|
+
description: "n8n INodeProperties array"
|
|
892
|
+
items: { $ref: "#/components/schemas/Field" }
|
|
893
|
+
authenticate:
|
|
894
|
+
type: object
|
|
895
|
+
nullable: true
|
|
896
|
+
description: "n8n IAuthenticateGeneric"
|
|
897
|
+
properties:
|
|
898
|
+
type: { type: string, enum: [generic] }
|
|
899
|
+
properties: { type: object, additionalProperties: true }
|
|
900
|
+
generic_auth: { type: boolean }
|
|
901
|
+
supported_nodes: { type: array, items: { type: string } }
|
|
902
|
+
http_request_node:
|
|
903
|
+
type: object
|
|
904
|
+
nullable: true
|
|
905
|
+
properties:
|
|
906
|
+
name: { type: string }
|
|
907
|
+
docsUrl: { type: string }
|
|
908
|
+
apiBaseUrl: { type: string }
|
|
909
|
+
apiBaseUrlPlaceholder: { type: string }
|
|
910
|
+
hidden: { type: boolean }
|
|
911
|
+
__overwritten_properties: { type: array, items: { type: string }, description: "fields sourced from external secrets manager" }
|
|
912
|
+
__skip_managed_creation: { type: boolean }
|
|
913
|
+
actions:
|
|
914
|
+
type: array
|
|
915
|
+
description: "declarative manifest of what this connector can DO with a credential — design-time discovery for the picker/builder UI"
|
|
916
|
+
items: { $ref: "#/components/schemas/Action" }
|
|
917
|
+
connector:
|
|
918
|
+
type: object
|
|
919
|
+
properties:
|
|
920
|
+
base_url: { type: string }
|
|
921
|
+
webhook_style: { type: string, enum: [app_level, per_grant] }
|
|
922
|
+
rate_limit: { type: object, nullable: true }
|
|
923
|
+
authorize_url: { type: string, nullable: true }
|
|
924
|
+
authorize_json_url: { type: string, nullable: true }
|
|
925
|
+
redirect_uri: { type: string, nullable: true }
|
|
926
|
+
test_supported: { type: boolean }
|
|
927
|
+
mcp:
|
|
928
|
+
type: object
|
|
929
|
+
nullable: true
|
|
930
|
+
description: "Present for remote MCP connectors, including clickup. URL templates use :id for the credential ID; provider endpoint/authentication values are fixed when present."
|
|
931
|
+
properties:
|
|
932
|
+
server_url: { type: string, format: uri }
|
|
933
|
+
auth_mode: { type: string, enum: [none, bearer, headers, oauth] }
|
|
934
|
+
protocol_version: { type: string }
|
|
935
|
+
tools_url: { type: string }
|
|
936
|
+
call_url: { type: string }
|
|
937
|
+
resume_url: { type: string }
|
|
938
|
+
authorize_url: { type: string }
|
|
939
|
+
|
|
940
|
+
ActionResult:
|
|
941
|
+
type: object
|
|
942
|
+
description: "envelope returned by every action invocation — same shape on success and failure"
|
|
943
|
+
properties:
|
|
944
|
+
status: { type: string, enum: [ok, error] }
|
|
945
|
+
action: { type: string, description: "action key" }
|
|
946
|
+
data: { type: object, additionalProperties: true, description: "present when status=ok" }
|
|
947
|
+
error:
|
|
948
|
+
type: object
|
|
949
|
+
description: "present when status=error"
|
|
950
|
+
properties:
|
|
951
|
+
type:
|
|
952
|
+
type: string
|
|
953
|
+
enum: [invalid_params, authentication_failed, forbidden, rate_limited, api_error]
|
|
954
|
+
message: { type: string }
|
|
955
|
+
status: { type: integer, nullable: true, description: "provider HTTP status" }
|
|
956
|
+
missing: { type: array, items: { type: string }, description: "invalid_params: required keys not supplied" }
|
|
957
|
+
unknown: { type: array, items: { type: string }, description: "invalid_params: keys not on the schema" }
|
|
958
|
+
retry_after: { type: integer, nullable: true, description: "rate_limited: seconds until next retry" }
|
|
959
|
+
body: { type: object, additionalProperties: true, nullable: true, description: "api_error: raw provider response" }
|
|
960
|
+
|
|
961
|
+
Action:
|
|
962
|
+
type: object
|
|
963
|
+
description: "one thing a connector can DO with a credential (n8n operation / Activepieces action)"
|
|
964
|
+
properties:
|
|
965
|
+
name: { type: string, description: "machine key, e.g. send_email" }
|
|
966
|
+
display_name: { type: string }
|
|
967
|
+
description: { type: string }
|
|
968
|
+
deprecated: { type: boolean }
|
|
969
|
+
tags: { type: array, items: { type: string } }
|
|
970
|
+
properties:
|
|
971
|
+
type: array
|
|
972
|
+
description: "input schema — same shape as credential properties"
|
|
973
|
+
items: { $ref: "#/components/schemas/Field" }
|
|
974
|
+
output:
|
|
975
|
+
type: array
|
|
976
|
+
description: "shape of the value the action returns (Activepieces returns: …)"
|
|
977
|
+
items: { $ref: "#/components/schemas/Field" }
|
|
978
|
+
|
|
979
|
+
Field:
|
|
980
|
+
type: object
|
|
981
|
+
description: "n8n INodeProperties — frontend renders the form from this"
|
|
982
|
+
properties:
|
|
983
|
+
name: { type: string }
|
|
984
|
+
displayName: { type: string }
|
|
985
|
+
type:
|
|
986
|
+
type: string
|
|
987
|
+
enum:
|
|
988
|
+
- string
|
|
989
|
+
- number
|
|
990
|
+
- boolean
|
|
991
|
+
- options
|
|
992
|
+
- multiOptions
|
|
993
|
+
- json
|
|
994
|
+
- hidden
|
|
995
|
+
- notice
|
|
996
|
+
- collection
|
|
997
|
+
- fixedCollection
|
|
998
|
+
- dateTime
|
|
999
|
+
- color
|
|
1000
|
+
- resourceLocator
|
|
1001
|
+
- resourceMapper
|
|
1002
|
+
- filter
|
|
1003
|
+
- assignmentCollection
|
|
1004
|
+
default: {}
|
|
1005
|
+
placeholder: { type: string }
|
|
1006
|
+
description: { type: string }
|
|
1007
|
+
hint: { type: string }
|
|
1008
|
+
required: { type: boolean }
|
|
1009
|
+
noDataExpression: { type: boolean }
|
|
1010
|
+
typeOptions: { type: object, additionalProperties: true, description: "password, expirable, redactJsonLeaves, resolvable_field, ..." }
|
|
1011
|
+
displayOptions:
|
|
1012
|
+
type: object
|
|
1013
|
+
additionalProperties: true
|
|
1014
|
+
description: "show/hide rules with _cnd predicates (n8n IDisplayOptions)"
|
|
1015
|
+
options:
|
|
1016
|
+
type: array
|
|
1017
|
+
items: { type: object, additionalProperties: true }
|
|
1018
|
+
|
|
1019
|
+
Credential:
|
|
1020
|
+
type: object
|
|
1021
|
+
properties:
|
|
1022
|
+
id: { type: string, format: uuid }
|
|
1023
|
+
type: { type: string, description: "connector key (n8n vocabulary)" }
|
|
1024
|
+
connector_key: { type: string, deprecated: true }
|
|
1025
|
+
name: { type: string, description: "display name" }
|
|
1026
|
+
external_account_id: { type: string, nullable: true }
|
|
1027
|
+
status: { type: string, enum: [active, expired, revoked, errored] }
|
|
1028
|
+
expires_at: { type: string, format: date-time, nullable: true }
|
|
1029
|
+
last_used_at: { type: string, format: date-time, nullable: true }
|
|
1030
|
+
created_at: { type: string, format: date-time }
|
|
1031
|
+
updated_at: { type: string, format: date-time }
|
|
1032
|
+
scopes: { type: array, items: { type: string }, nullable: true }
|
|
1033
|
+
is_managed: { type: boolean }
|
|
1034
|
+
external_ref: { type: string, nullable: true }
|
|
1035
|
+
__overwritten_properties: { type: array, items: { type: string } }
|
|
1036
|
+
data:
|
|
1037
|
+
type: object
|
|
1038
|
+
additionalProperties: true
|
|
1039
|
+
description: "With include_data=true, decrypted data for the owner role only; shared viewers/editors omit data. MCP returns only public configuration for all visible connections."
|
|
1040
|
+
|
|
1041
|
+
SharePayload:
|
|
1042
|
+
type: object
|
|
1043
|
+
required: [principal_type, principal_id]
|
|
1044
|
+
properties:
|
|
1045
|
+
principal_type: { type: string, description: "host-defined type, e.g. User/Team/Project" }
|
|
1046
|
+
principal_id: { type: string, format: uuid }
|
|
1047
|
+
role: { type: string, enum: [viewer, editor, owner], default: viewer }
|
|
1048
|
+
|
|
1049
|
+
CredentialShare:
|
|
1050
|
+
type: object
|
|
1051
|
+
properties:
|
|
1052
|
+
id: { type: string, format: uuid }
|
|
1053
|
+
grant_id: { type: string, format: uuid }
|
|
1054
|
+
principal_type: { type: string }
|
|
1055
|
+
principal_id: { type: string, format: uuid }
|
|
1056
|
+
role: { type: string, enum: [viewer, editor, owner] }
|
|
1057
|
+
|
|
1058
|
+
TestResult:
|
|
1059
|
+
type: object
|
|
1060
|
+
properties:
|
|
1061
|
+
status: { type: string, enum: [OK, ERROR] }
|
|
1062
|
+
message: { type: string, nullable: true }
|
|
1063
|
+
detail: { type: object, additionalProperties: true, nullable: true }
|
|
1064
|
+
|
|
1065
|
+
Error:
|
|
1066
|
+
type: object
|
|
1067
|
+
properties:
|
|
1068
|
+
error: { type: string }
|
|
1069
|
+
|
|
1070
|
+
responses:
|
|
1071
|
+
McpRateLimited:
|
|
1072
|
+
description: Upstream rate limit; the operation is not automatically replayed
|
|
1073
|
+
headers:
|
|
1074
|
+
Retry-After:
|
|
1075
|
+
description: Valid upstream delay-seconds or HTTP date; omitted if unavailable
|
|
1076
|
+
schema: { type: string }
|
|
1077
|
+
content:
|
|
1078
|
+
application/json:
|
|
1079
|
+
schema: { $ref: "#/components/schemas/McpError" }
|
|
1080
|
+
McpFailure:
|
|
1081
|
+
description: Typed MCP failure; authorization_required can include an encrypted consent context.
|
|
1082
|
+
content:
|
|
1083
|
+
application/json:
|
|
1084
|
+
schema: { $ref: "#/components/schemas/McpError" }
|
|
1085
|
+
Unauthorized:
|
|
1086
|
+
description: Unauthorized (missing owner, role gate, or signature)
|
|
1087
|
+
content: { application/json: { schema: { $ref: "#/components/schemas/Error" } } }
|
|
1088
|
+
NotFound:
|
|
1089
|
+
description: Resource or connector type not found
|
|
1090
|
+
content: { application/json: { schema: { $ref: "#/components/schemas/Error" } } }
|
|
1091
|
+
WebhookAccepted:
|
|
1092
|
+
description: Event accepted and queued
|
|
1093
|
+
content:
|
|
1094
|
+
application/json:
|
|
1095
|
+
schema:
|
|
1096
|
+
type: object
|
|
1097
|
+
properties:
|
|
1098
|
+
event_id: { type: string, format: uuid }
|
|
1099
|
+
status: { type: string, enum: [accepted, duplicate] }
|