{
	"openapi": "3.1.0",
	"info": {
		"title": "Outvoy API",
		"description": "LinkedIn outreach for agents and developers: senders, audiences, campaigns, inbox and events. Authenticate with `Authorization: Bearer ov_…` (an API key from the console). Errors answer `{ errorCode, message, details? }`. Writes accept an `Idempotency-Key` header.",
		"version": "1.0.0"
	},
	"security": [
		{
			"bearerAuth": []
		}
	],
	"servers": [
		{
			"url": "https://api.getoutvoy.com",
			"description": "Outvoy API"
		}
	],
	"tags": [
		{
			"name": "Auth"
		},
		{
			"name": "Connect"
		},
		{
			"name": "Data"
		},
		{
			"name": "Workspace"
		},
		{
			"name": "API keys"
		},
		{
			"name": "Events"
		},
		{
			"name": "Webhooks"
		},
		{
			"name": "Licences"
		},
		{
			"name": "Billing"
		},
		{
			"name": "Support"
		},
		{
			"name": "Senders"
		},
		{
			"name": "Leads"
		},
		{
			"name": "Lists"
		},
		{
			"name": "Imports"
		},
		{
			"name": "Search"
		},
		{
			"name": "Blocklist"
		},
		{
			"name": "Campaigns"
		},
		{
			"name": "Enrollments"
		},
		{
			"name": "Inbox"
		}
	],
	"paths": {
		"/auth/sign-up": {
			"post": {
				"operationId": "signUp",
				"tags": ["Auth"],
				"summary": "Create an account and its workspace",
				"description": "Creates the user and a workspace with no plan yet (start the 7-day trial or redeem a licence to act), and returns a session.",
				"responses": {
					"200": {
						"description": "A console session (JWT, 8 hours)",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "object",
											"properties": {
												"token": {
													"type": "string"
												},
												"expiresAt": {
													"type": "string",
													"format": "date-time"
												},
												"user": {
													"$ref": "#/components/schemas/User"
												}
											},
											"required": ["token", "expiresAt", "user"]
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/SignUpInput"
							}
						}
					}
				},
				"security": [],
				"parameters": []
			}
		},
		"/auth/sign-in": {
			"post": {
				"operationId": "signIn",
				"tags": ["Auth"],
				"summary": "Sign in with email and password",
				"responses": {
					"200": {
						"description": "A console session (JWT, 8 hours)",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "object",
											"properties": {
												"token": {
													"type": "string"
												},
												"expiresAt": {
													"type": "string",
													"format": "date-time"
												},
												"user": {
													"$ref": "#/components/schemas/User"
												}
											},
											"required": ["token", "expiresAt", "user"]
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/SignInInput"
							}
						}
					}
				},
				"security": [],
				"parameters": []
			}
		},
		"/connect/{code}": {
			"get": {
				"operationId": "getConnectLink",
				"tags": ["Connect"],
				"summary": "Read a connect link",
				"description": "Public (the code is the credential). Which workspace and sender the link connects, whether it is `pending`, `connected` (with `connectedAs`) or `expired`. Unknown codes answer 404. Rate-limited per IP.",
				"responses": {
					"200": {
						"description": "The link",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/ConnectLink"
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": [
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "code",
						"required": true,
						"description": "The code's id."
					}
				],
				"security": []
			}
		},
		"/connect/{code}/start": {
			"post": {
				"operationId": "startConnectLink",
				"tags": ["Connect"],
				"summary": "Open the LinkedIn sign-in for a connect link",
				"description": "Public. Creates the hosted LinkedIn sign-in page now (it expires within the day, so it is never made ahead of time) and answers its URL; when the owner finishes, the browser comes back to the console's /c/{code}/done. 404 for unknown or expired codes, 409 when the link was already used, 503 when this server has no LinkedIn provider.",
				"responses": {
					"200": {
						"description": "Where to send the browser",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "object",
											"properties": {
												"url": {
													"type": "string",
													"format": "uri",
													"description": "Where to send the browser: the hosted LinkedIn sign-in page. It comes back to the console's /c/<code>/done when finished."
												}
											},
											"required": ["url"]
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": [
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "code",
						"required": true,
						"description": "The code's id."
					}
				],
				"security": []
			}
		},
		"/connect/{code}/dev-signin": {},
		"/exports/{exportId}/download": {
			"get": {
				"operationId": "downloadDataExport",
				"tags": ["Data"],
				"summary": "Download a workspace export's archive",
				"description": "The URL comes from a ready export's `downloadUrl` (GET /v1/exports/{exportId}); it is signed, names one export and works for 15 minutes. Answers the ZIP archive. A wrong or expired link answers 403 DATA_EXPORT_LINK_INVALID_ERROR; an archive already deleted, 409 DATA_EXPORT_NOT_READY_ERROR.",
				"security": [],
				"responses": {
					"200": {
						"description": "The ZIP archive",
						"content": {
							"application/zip": {
								"schema": {
									"type": "string",
									"format": "binary"
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": [
					{
						"name": "expires",
						"in": "query",
						"required": true,
						"description": "Unix seconds after which the link stops working.",
						"schema": {
							"type": "string",
							"pattern": "^\\d+$"
						}
					},
					{
						"name": "signature",
						"in": "query",
						"required": true,
						"description": "The link's signature.",
						"schema": {
							"type": "string",
							"pattern": "^[0-9a-f]{64}$"
						}
					},
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "exportId",
						"required": true,
						"description": "The export's id."
					}
				]
			}
		},
		"/v1/me": {
			"get": {
				"operationId": "getMe",
				"tags": ["Workspace"],
				"summary": "Who am I",
				"description": "The workspace with its plan, limits and usage, and the user or API key making the call.",
				"responses": {
					"200": {
						"description": "The caller and their workspace",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "object",
											"properties": {
												"user": {
													"$ref": "#/components/schemas/User"
												},
												"workspace": {
													"$ref": "#/components/schemas/Workspace"
												},
												"apiKey": {
													"type": "object",
													"properties": {
														"id": {
															"type": "string"
														},
														"name": {
															"type": "string"
														}
													},
													"required": ["id", "name"],
													"description": "The key making the call, when it is one."
												}
											},
											"required": ["workspace"]
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": []
			}
		},
		"/v1/workspace": {
			"patch": {
				"operationId": "updateWorkspace",
				"tags": ["Workspace"],
				"summary": "Rename the workspace",
				"responses": {
					"200": {
						"description": "The workspace",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "object",
											"properties": {
												"id": {
													"type": "string"
												},
												"name": {
													"type": "string"
												}
											},
											"required": ["id", "name"]
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/UpdateWorkspaceInput"
							}
						}
					}
				},
				"parameters": [
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			},
			"delete": {
				"operationId": "deleteWorkspace",
				"tags": ["Workspace"],
				"summary": "Delete the workspace and everything in it (console session only)",
				"description": "Permanent, immediate and irreversible (GDPR art. 17). Confirm with the workspace's exact name. Before anything is deleted, every LinkedIn account its senders connected is disconnected at the provider, every live monthly subscription is set to end with its period (no further charge) and an AppSumo licence is released so it can be redeemed again; if a provider refuses, nothing is deleted (502 WORKSPACE_DELETION_BLOCKED_ERROR) and you can retry. Then every lead, list, campaign, conversation, sender, key, webhook, event and export of the workspace is deleted, with the accounts of its members. Export the data first if you want a copy (POST /v1/exports). Workspace owners only, from a console session (403 with an API key).",
				"responses": {
					"200": {
						"description": "What was deleted",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "object",
											"properties": {
												"workspaceId": {
													"type": "string"
												},
												"deleted": {
													"type": "boolean",
													"enum": [true]
												},
												"linkedinAccountsRemoved": {
													"type": "integer",
													"description": "LinkedIn accounts disconnected at the provider (their sessions are gone)."
												},
												"subscriptionsCanceled": {
													"type": "integer",
													"description": "Monthly subscriptions set to end: no further charge. Stripe keeps its own invoices."
												},
												"licensesReleased": {
													"type": "integer",
													"description": "Lifetime licences detached from the workspace; they can be redeemed again in a new workspace from AppSumo."
												},
												"usersDeleted": {
													"type": "integer",
													"description": "Accounts deleted with the workspace (members of no other workspace)."
												}
											},
											"required": [
												"workspaceId",
												"deleted",
												"linkedinAccountsRemoved",
												"subscriptionsCanceled",
												"licensesReleased",
												"usersDeleted"
											]
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/DeleteWorkspaceInput"
							}
						}
					}
				},
				"parameters": [
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			}
		},
		"/v1/api-keys": {
			"get": {
				"operationId": "listApiKeys",
				"tags": ["API keys"],
				"summary": "List API keys (console session only)",
				"responses": {
					"200": {
						"description": "Every key of the workspace, revoked ones included",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "array",
											"items": {
												"$ref": "#/components/schemas/ApiKey"
											}
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": []
			},
			"post": {
				"operationId": "createApiKey",
				"tags": ["API keys"],
				"summary": "Create an API key (console session only)",
				"description": "The secret is in this response only. API keys cannot create keys.",
				"responses": {
					"200": {
						"description": "The new key with its secret",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/CreatedApiKey"
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/CreateApiKeyInput"
							}
						}
					}
				},
				"parameters": [
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			}
		},
		"/v1/api-keys/{apiKeyId}": {
			"delete": {
				"operationId": "revokeApiKey",
				"tags": ["API keys"],
				"summary": "Revoke an API key (console session only)",
				"responses": {
					"200": {
						"description": "The revoked key",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "object",
											"properties": {
												"id": {
													"type": "string"
												},
												"revokedAt": {
													"type": "string",
													"format": "date-time"
												}
											},
											"required": ["id", "revokedAt"]
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": [
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "apiKeyId",
						"required": true,
						"description": "The api key's id."
					},
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			}
		},
		"/v1/events": {
			"get": {
				"operationId": "listEvents",
				"tags": ["Events"],
				"summary": "Read the event feed",
				"description": "Oldest first after ?after=; without it, the latest page. Keep calling with meta.nextCursor to follow the feed.",
				"responses": {
					"200": {
						"description": "A page of events",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "array",
											"items": {
												"$ref": "#/components/schemas/Event"
											}
										},
										"meta": {
											"allOf": [
												{
													"$ref": "#/components/schemas/PageMeta"
												},
												{
													"type": "object",
													"properties": {
														"prevCursor": {
															"type": "string",
															"description": "The oldest event of this page: pass it as ?before= to read further back. Absent on an empty page."
														}
													}
												}
											]
										}
									},
									"required": ["data", "meta"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": [
					{
						"name": "after",
						"in": "query",
						"required": false,
						"description": "Return events after this event id (exclusive).",
						"schema": {
							"type": "string"
						}
					},
					{
						"name": "before",
						"in": "query",
						"required": false,
						"description": "Return the page of events just before this event id (exclusive), to read back in time. Don't combine with after.",
						"schema": {
							"type": "string"
						}
					},
					{
						"name": "types",
						"in": "query",
						"required": false,
						"description": "Comma-separated event types, e.g. lead.replied,lead.invite_accepted",
						"schema": {
							"type": "string"
						}
					},
					{
						"name": "limit",
						"in": "query",
						"required": false,
						"schema": {
							"type": "integer",
							"minimum": 1,
							"maximum": 100,
							"default": 50
						}
					}
				]
			}
		},
		"/v1/webhooks": {
			"get": {
				"operationId": "listWebhooks",
				"tags": ["Webhooks"],
				"summary": "List webhook endpoints",
				"responses": {
					"200": {
						"description": "Every endpoint of the workspace",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "array",
											"items": {
												"$ref": "#/components/schemas/WebhookEndpoint"
											}
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": []
			},
			"post": {
				"operationId": "createWebhook",
				"tags": ["Webhooks"],
				"summary": "Create a webhook endpoint",
				"description": "Outvoy POSTs `{ id, type, occurredAt, data }` to the URL for each matching event, with `Outvoy-Signature: t=<unix>,v1=<hex HMAC-SHA256(secret, \"<t>.<body>\")>` and `Outvoy-Event-Id`. Answer 2xx within 10 s; anything else is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 12 h and 24 h (8 attempts). 50 failures in a row disable the endpoint. The signing secret is in this response only (and on rotate-secret).",
				"responses": {
					"200": {
						"description": "The endpoint and its secret",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/WebhookEndpointWithSecret"
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/CreateWebhookEndpointInput"
							}
						}
					}
				},
				"parameters": [
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			}
		},
		"/v1/webhooks/{webhookEndpointId}": {
			"get": {
				"operationId": "getWebhook",
				"tags": ["Webhooks"],
				"summary": "Get a webhook endpoint",
				"responses": {
					"200": {
						"description": "The endpoint",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/WebhookEndpoint"
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": [
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "webhookEndpointId",
						"required": true,
						"description": "The webhook endpoint's id."
					}
				]
			},
			"patch": {
				"operationId": "updateWebhook",
				"tags": ["Webhooks"],
				"summary": "Update a webhook endpoint",
				"description": "Change the URL, description or event types, or enable/disable it. Re-enabling resets the failure streak and resumes pending retries.",
				"responses": {
					"200": {
						"description": "The endpoint",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/WebhookEndpoint"
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"requestBody": {
					"required": false,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/UpdateWebhookEndpointInput"
							}
						}
					}
				},
				"parameters": [
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "webhookEndpointId",
						"required": true,
						"description": "The webhook endpoint's id."
					},
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			},
			"delete": {
				"operationId": "deleteWebhook",
				"tags": ["Webhooks"],
				"summary": "Delete a webhook endpoint",
				"description": "Its delivery log and pending retries go with it.",
				"responses": {
					"200": {
						"description": "Deleted",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "object",
											"properties": {
												"id": {
													"type": "string"
												},
												"deleted": {
													"type": "boolean",
													"enum": [true]
												}
											},
											"required": ["id", "deleted"]
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": [
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "webhookEndpointId",
						"required": true,
						"description": "The webhook endpoint's id."
					},
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			}
		},
		"/v1/webhooks/{webhookEndpointId}/rotate-secret": {
			"post": {
				"operationId": "rotateWebhookSecret",
				"tags": ["Webhooks"],
				"summary": "Rotate the signing secret",
				"description": "A new secret signs every request from now on; the old one stops at once. Shown in this response only.",
				"responses": {
					"200": {
						"description": "The endpoint and its new secret",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/WebhookEndpointWithSecret"
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": [
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "webhookEndpointId",
						"required": true,
						"description": "The webhook endpoint's id."
					},
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			}
		},
		"/v1/webhooks/{webhookEndpointId}/deliveries": {
			"get": {
				"operationId": "listWebhookDeliveries",
				"tags": ["Webhooks"],
				"summary": "List delivery attempts",
				"description": "Every attempt to this endpoint, newest first, with the response status, the first 2 KB of the response and when the retry is due.",
				"responses": {
					"200": {
						"description": "A page of attempts",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "array",
											"items": {
												"$ref": "#/components/schemas/WebhookDelivery"
											}
										},
										"meta": {
											"$ref": "#/components/schemas/PageMeta"
										}
									},
									"required": ["data", "meta"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": [
					{
						"name": "cursor",
						"in": "query",
						"required": false,
						"description": "Opaque cursor from the previous page's meta.nextCursor.",
						"schema": {
							"type": "string",
							"minLength": 1
						}
					},
					{
						"name": "limit",
						"in": "query",
						"required": false,
						"description": "Page size, 1–100 (default 50).",
						"schema": {
							"type": "integer",
							"minimum": 1,
							"maximum": 100,
							"default": 50
						}
					},
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "webhookEndpointId",
						"required": true,
						"description": "The webhook endpoint's id."
					}
				]
			}
		},
		"/v1/webhooks/{webhookEndpointId}/test": {
			"post": {
				"operationId": "testWebhook",
				"tags": ["Webhooks"],
				"summary": "Send a test ping",
				"description": "Sends a signed `webhook.test` event now and answers with the attempt. Not retried, and it doesn't count towards the failure streak.",
				"responses": {
					"200": {
						"description": "The attempt",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/WebhookDelivery"
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": [
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "webhookEndpointId",
						"required": true,
						"description": "The webhook endpoint's id."
					},
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			}
		},
		"/v1/licenses": {
			"get": {
				"operationId": "getLicense",
				"tags": ["Licences"],
				"summary": "The workspace's licence",
				"responses": {
					"200": {
						"description": "The active licence, if any, and the plan",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "object",
											"properties": {
												"license": {
													"$ref": "#/components/schemas/License"
												},
												"plan": {
													"type": "string",
													"enum": [
														"none",
														"starter",
														"growth",
														"scale",
														"tier_1",
														"tier_2",
														"tier_3",
														"tier_4"
													]
												}
											},
											"required": ["plan"]
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": []
			}
		},
		"/v1/licenses/redeem": {
			"post": {
				"operationId": "redeemLicense",
				"tags": ["Licences"],
				"summary": "Redeem a licence (console session only)",
				"description": "Attaches the AppSumo licence behind the one-time token to this workspace and moves it to the licence's plan. One licence per workspace; a licence attached elsewhere is refused.",
				"responses": {
					"200": {
						"description": "The attached licence",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/License"
										},
										"notice": {
											"type": "string",
											"description": "Something the person should know, e.g. that their monthly subscription was set to end because the licence replaces it."
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/RedeemLicenseInput"
							}
						}
					}
				},
				"parameters": [
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			}
		},
		"/v1/billing": {
			"get": {
				"operationId": "getBilling",
				"tags": ["Billing"],
				"summary": "The workspace's billing",
				"description": "The plan, where it comes from (`subscription`, `license` or `none`), the subscription's status, trial end, next charge and price. Readable with an API key; starting or changing a subscription is done by a person in the console.",
				"responses": {
					"200": {
						"description": "The billing state",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/Billing"
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": []
			}
		},
		"/v1/billing/checkout": {
			"post": {
				"operationId": "startCheckout",
				"tags": ["Billing"],
				"summary": "Start the 7-day free trial (console session only)",
				"description": "A Stripe Checkout URL for a monthly plan: the card is collected now and charged on day 8 unless the subscription is cancelled. A workspace that already had a subscription subscribes without a trial. Refused (409) on a lifetime licence or while a subscription is live; 503 when billing is not configured; 403 with an API key.",
				"responses": {
					"200": {
						"description": "Where to send the browser",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "object",
											"properties": {
												"url": {
													"type": "string",
													"format": "uri",
													"description": "Send the browser here (Stripe's hosted page)."
												}
											},
											"required": ["url"]
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/StartCheckoutInput"
							}
						}
					}
				},
				"parameters": [
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			}
		},
		"/v1/billing/portal": {
			"post": {
				"operationId": "openBillingPortal",
				"tags": ["Billing"],
				"summary": "Manage billing (console session only)",
				"description": "A Stripe customer portal URL: payment method, invoices, plan changes and cancellation. 409 before the first checkout.",
				"responses": {
					"200": {
						"description": "Where to send the browser",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "object",
											"properties": {
												"url": {
													"type": "string",
													"format": "uri",
													"description": "Send the browser here (Stripe's hosted page)."
												}
											},
											"required": ["url"]
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": [
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			}
		},
		"/v1/billing/extra-senders": {
			"post": {
				"operationId": "setExtraSenders",
				"tags": ["Billing"],
				"summary": "Set the extra LinkedIn accounts (console session only)",
				"description": "Every AppSumo lifetime licence includes 1 LinkedIn account; each extra one is a monthly add-on (the price is in `GET /v1/billing` → `extraSenders.priceUsdPerMonth`). With no add-on yet, the answer is a Stripe Checkout `url` and the accounts arrive once Stripe confirms the payment; with one, its quantity changes now (prorated on the next invoice); `0` cancels it at the end of its paid period, keeping its accounts until then. Refused (409) below the LinkedIn senders connected beyond the included one (disconnect senders first) and on a workspace without a lifetime licence (monthly plans move to a bigger plan instead); 503 when the add-on is not configured; 403 with an API key. Never changes the licence.",
				"responses": {
					"200": {
						"description": "What happened",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "object",
											"properties": {
												"outcome": {
													"type": "string",
													"enum": [
														"checkout",
														"updated",
														"canceled",
														"unchanged"
													],
													"description": "`checkout`: no add-on yet, send the browser to `url` to pay; `updated`: the add-on's quantity changed now (prorated on the next invoice); `canceled`: the add-on ends with its paid period; `unchanged`: it already was so."
												},
												"url": {
													"type": "string",
													"format": "uri",
													"description": "Only for `checkout`: Stripe's hosted page."
												},
												"extraSenders": {
													"type": "integer",
													"description": "Extra LinkedIn accounts in effect now (a checkout adds them once Stripe confirms the payment)."
												}
											},
											"required": ["outcome", "extraSenders"]
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/SetExtraSendersInput"
							}
						}
					}
				},
				"parameters": [
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			}
		},
		"/v1/support/identity": {
			"get": {
				"operationId": "getSupportIdentity",
				"tags": ["Support"],
				"summary": "Support chat identity (console session only)",
				"description": "The signed-in user's email for the support chat, with its verification signature and session token when verification is configured. 403 with an API key.",
				"responses": {
					"200": {
						"description": "The identity to give the support chat",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/SupportIdentity"
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": []
			}
		},
		"/v1/exports": {
			"get": {
				"operationId": "listDataExports",
				"tags": ["Data"],
				"summary": "List workspace exports (console session only)",
				"description": "The last 10 exports, newest first. Ready ones carry a fresh `downloadUrl`, valid for 15 minutes. Console session of a workspace owner only (403 SESSION_REQUIRED_ERROR with an API key, 403 WORKSPACE_OWNER_REQUIRED_ERROR for other members): the archive holds everything at once, so a leaked key can't take it. Agents read each resource through its own endpoints.",
				"responses": {
					"200": {
						"description": "The exports",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "array",
											"items": {
												"$ref": "#/components/schemas/DataExport"
											}
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": []
			},
			"post": {
				"operationId": "requestDataExport",
				"tags": ["Data"],
				"summary": "Export the whole workspace (console session only)",
				"description": "Queues a ZIP archive of everything the workspace holds — leads (JSON and CSV), lists, campaigns, enrollments, the actions history, conversations and messages, senders, blocklist, events, webhook endpoints, imports, API key metadata, billing and users — with a README.json describing every file. It is usually ready within a minute: poll GET /v1/exports/{exportId} until `status` is `ready`, then open `downloadUrl`. Archives are deleted after 7 days. Secrets (password and key hashes, webhook secrets) are never included. One export at a time: 409 DATA_EXPORT_IN_PROGRESS_ERROR while one is queued or running. Console session of a workspace owner only (403 SESSION_REQUIRED_ERROR with an API key, 403 WORKSPACE_OWNER_REQUIRED_ERROR for other members): the archive holds everything at once, so a leaked key can't take it. Agents read each resource through its own endpoints.",
				"responses": {
					"200": {
						"description": "The queued export",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/DataExport"
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": [
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			}
		},
		"/v1/exports/{exportId}": {
			"get": {
				"operationId": "getDataExport",
				"tags": ["Data"],
				"summary": "Read a workspace export (console session only)",
				"description": "Its status and, once ready, a signed `downloadUrl` valid for 15 minutes (read it again for a new one). Console session of a workspace owner only (403 SESSION_REQUIRED_ERROR with an API key, 403 WORKSPACE_OWNER_REQUIRED_ERROR for other members): the archive holds everything at once, so a leaked key can't take it. Agents read each resource through its own endpoints.",
				"responses": {
					"200": {
						"description": "The export",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/DataExport"
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": [
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "exportId",
						"required": true,
						"description": "The export's id."
					}
				]
			}
		},
		"/v1/senders": {
			"get": {
				"operationId": "listSenders",
				"tags": ["Senders"],
				"summary": "List senders",
				"description": "Every sender except disconnected ones, with limits, effective limits (warm-up applied), schedule and today's usage.",
				"responses": {
					"200": {
						"description": "The senders",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "array",
											"items": {
												"$ref": "#/components/schemas/Sender"
											}
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": []
			}
		},
		"/v1/senders/connect-link": {
			"post": {
				"operationId": "createSenderConnectLink",
				"tags": ["Senders"],
				"summary": "Get a LinkedIn connect link",
				"description": "Returns Outvoy's short connect link (`…/c/<code>`, valid 7 days) for the account owner to open: it names the workspace and leads to a hosted page where they sign in to LinkedIn (credentials, 2FA and checkpoints are handled there, never by Outvoy), created when they click. The sender is created `connecting` and becomes `active` (event sender.connected) when LinkedIn confirms; agents wait with the MCP tool wait_for_connection. Pass reconnectSenderId to repair a sender in `needs_reconnect` (its open link is reused). 402 when the plan has no LinkedIn sender left; 503 when this server has no LinkedIn provider configured (use a sandbox sender).",
				"responses": {
					"200": {
						"description": "The link and the sender it connects",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "object",
											"properties": {
												"senderId": {
													"type": "string",
													"description": "The sender the link connects. It stays `connecting` (or `needs_reconnect`) until LinkedIn confirms."
												},
												"url": {
													"type": "string",
													"format": "uri",
													"description": "Outvoy's short connect link (`…/c/<code>`). Give it to the account owner: they open it in a browser, sign in to LinkedIn on the hosted page it leads to (credentials and 2FA never reach Outvoy) and come back. Valid for 7 days; the hosted sign-in page itself is created when they click.",
													"example": "https://getoutvoy.com/c/7KQ2M9XH4P"
												},
												"code": {
													"type": "string",
													"description": "The link's code, the last part of `url`.",
													"example": "7KQ2M9XH4P"
												},
												"expiresAt": {
													"type": "string",
													"format": "date-time",
													"description": "When the link stops working (7 days after it was made)."
												}
											},
											"required": ["senderId", "url", "code", "expiresAt"]
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"requestBody": {
					"required": false,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/CreateSenderConnectLinkInput"
							}
						}
					}
				},
				"parameters": [
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			}
		},
		"/v1/senders/sandbox": {
			"post": {
				"operationId": "createSandboxSender",
				"tags": ["Senders"],
				"summary": "Create a sandbox sender",
				"description": "A simulated LinkedIn account, active at once: it searches a fixed simulated population, invitations are accepted after a simulated delay (about 45% of people accept), some people reply to messages, and time runs compressed (a simulated day per real minute by default). Nothing reaches LinkedIn. 402 when the plan's sandbox senders are used up.",
				"responses": {
					"200": {
						"description": "The new sender",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/Sender"
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"requestBody": {
					"required": false,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/CreateSandboxSenderInput"
							}
						}
					}
				},
				"parameters": [
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			}
		},
		"/v1/senders/{senderId}": {
			"get": {
				"operationId": "getSender",
				"tags": ["Senders"],
				"summary": "Get a sender",
				"responses": {
					"200": {
						"description": "The sender",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/Sender"
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": [
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "senderId",
						"required": true,
						"description": "The sender's id."
					}
				]
			},
			"patch": {
				"operationId": "updateSender",
				"tags": ["Senders"],
				"summary": "Update a sender's name, limits, schedule or warm-up",
				"description": "Limits merge over the current ones and stay within the hard ceilings (40 invites/day, 200/week, 150 messages/day, 150 profile views/day, 100 post likes/day).",
				"responses": {
					"200": {
						"description": "The sender",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/Sender"
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"requestBody": {
					"required": false,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/UpdateSenderInput"
							}
						}
					}
				},
				"parameters": [
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "senderId",
						"required": true,
						"description": "The sender's id."
					},
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			},
			"delete": {
				"operationId": "disconnectSender",
				"tags": ["Senders"],
				"summary": "Disconnect a sender",
				"description": "It stops acting for good and frees its plan slot. For a LinkedIn sender, the account's session is then deleted at our LinkedIn provider (Unipile), unless another sender still uses the same account; if the provider can't be reached the sender is disconnected anyway and the removal is retried in the background. The record stays (status disconnected) so history and conversations keep their sender; it no longer appears in GET /v1/senders. Connecting the account again later needs a new sign-in.",
				"responses": {
					"200": {
						"description": "The disconnected sender",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/Sender"
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": [
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "senderId",
						"required": true,
						"description": "The sender's id."
					},
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			}
		},
		"/v1/senders/{senderId}/pause": {
			"post": {
				"operationId": "pauseSender",
				"tags": ["Senders"],
				"summary": "Pause a sender",
				"description": "It stops acting in every campaign until resumed. Only an active sender can be paused (409 otherwise).",
				"responses": {
					"200": {
						"description": "The sender",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/Sender"
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": [
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "senderId",
						"required": true,
						"description": "The sender's id."
					},
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			}
		},
		"/v1/senders/{senderId}/resume": {
			"post": {
				"operationId": "resumeSender",
				"tags": ["Senders"],
				"summary": "Resume a paused sender",
				"responses": {
					"200": {
						"description": "The sender",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/Sender"
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": [
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "senderId",
						"required": true,
						"description": "The sender's id."
					},
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			}
		},
		"/v1/leads": {
			"get": {
				"operationId": "listLeads",
				"tags": ["Leads"],
				"summary": "List leads",
				"description": "The workspace's leads, or one list's with ?listId=; ?search= matches name, headline, company or profile identifier.",
				"responses": {
					"200": {
						"description": "A page of leads",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "array",
											"items": {
												"$ref": "#/components/schemas/Lead"
											}
										},
										"meta": {
											"$ref": "#/components/schemas/PageMeta"
										}
									},
									"required": ["data", "meta"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": [
					{
						"name": "cursor",
						"in": "query",
						"required": false,
						"description": "Opaque cursor from the previous page's meta.nextCursor.",
						"schema": {
							"type": "string",
							"minLength": 1
						}
					},
					{
						"name": "limit",
						"in": "query",
						"required": false,
						"description": "Page size, 1–100 (default 50).",
						"schema": {
							"type": "integer",
							"minimum": 1,
							"maximum": 100,
							"default": 50
						}
					},
					{
						"name": "search",
						"in": "query",
						"required": false,
						"description": "Matches name, headline, company or profile identifier.",
						"schema": {
							"type": "string",
							"maxLength": 200
						}
					},
					{
						"name": "listId",
						"in": "query",
						"required": false,
						"description": "Only leads in this list.",
						"schema": {
							"type": "string"
						}
					}
				]
			}
		},
		"/v1/leads/{leadId}": {
			"get": {
				"operationId": "getLead",
				"tags": ["Leads"],
				"summary": "Get a lead",
				"responses": {
					"200": {
						"description": "The lead",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/Lead"
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": [
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "leadId",
						"required": true,
						"description": "The lead's id."
					}
				]
			},
			"patch": {
				"operationId": "updateLead",
				"tags": ["Leads"],
				"summary": "Set a lead's custom fields",
				"description": "Fields are merged: keys you send are set, a key set to \"\" is removed, the rest stay. Templates read them as {{fields.key}}.",
				"responses": {
					"200": {
						"description": "The lead",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/Lead"
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/UpdateLeadInput"
							}
						}
					}
				},
				"parameters": [
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "leadId",
						"required": true,
						"description": "The lead's id."
					},
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			},
			"delete": {
				"operationId": "deleteLead",
				"tags": ["Leads"],
				"summary": "Delete a lead and everything about them",
				"description": "For a person's erasure request (GDPR art. 17). Permanent and immediate: their live enrollments stop first (nothing queued for them runs afterwards), then the lead, its list and campaign memberships, enrollments, actions, conversations and messages are deleted, and the public events that named them keep their ids but lose every personal field (`lead.redacted: true`). Ready workspace exports, which contain them, are expired. With `blocklist` (default true) their LinkedIn profile is added to the blocklist so no import or campaign brings them back; the blocklist keeps that profile identifier, as the suppression list that honours the request. Emits `lead.deleted` with the lead's id. The body is optional. API keys may call it.",
				"responses": {
					"200": {
						"description": "What was deleted",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/DeletedLead"
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"requestBody": {
					"required": false,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/DeleteLeadInput"
							}
						}
					}
				},
				"parameters": [
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "leadId",
						"required": true,
						"description": "The lead's id."
					},
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			}
		},
		"/v1/lists": {
			"get": {
				"operationId": "listLists",
				"tags": ["Lists"],
				"summary": "List lists",
				"responses": {
					"200": {
						"description": "Every list with its lead count, newest first",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "array",
											"items": {
												"$ref": "#/components/schemas/List"
											}
										},
										"meta": {
											"$ref": "#/components/schemas/PageMeta"
										}
									},
									"required": ["data", "meta"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": []
			},
			"post": {
				"operationId": "createList",
				"tags": ["Lists"],
				"summary": "Create a list",
				"responses": {
					"200": {
						"description": "The new list",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/List"
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/CreateListInput"
							}
						}
					}
				},
				"parameters": [
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			}
		},
		"/v1/lists/{listId}": {
			"get": {
				"operationId": "getList",
				"tags": ["Lists"],
				"summary": "Get a list",
				"responses": {
					"200": {
						"description": "The list",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/List"
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": [
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "listId",
						"required": true,
						"description": "The list's id."
					}
				]
			},
			"patch": {
				"operationId": "updateList",
				"tags": ["Lists"],
				"summary": "Rename or describe a list",
				"responses": {
					"200": {
						"description": "The list",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/List"
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"requestBody": {
					"required": false,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/UpdateListInput"
							}
						}
					}
				},
				"parameters": [
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "listId",
						"required": true,
						"description": "The list's id."
					},
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			},
			"delete": {
				"operationId": "deleteList",
				"tags": ["Lists"],
				"summary": "Delete a list",
				"description": "The list and its imports go; its leads stay in the workspace.",
				"responses": {
					"200": {
						"description": "Deleted",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "object",
											"properties": {
												"id": {
													"type": "string"
												},
												"deleted": {
													"type": "boolean",
													"enum": [true]
												}
											},
											"required": ["id", "deleted"]
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": [
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "listId",
						"required": true,
						"description": "The list's id."
					},
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			}
		},
		"/v1/lists/{listId}/leads": {
			"get": {
				"operationId": "listListLeads",
				"tags": ["Lists"],
				"summary": "List a list's leads",
				"responses": {
					"200": {
						"description": "A page of leads",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "array",
											"items": {
												"$ref": "#/components/schemas/Lead"
											}
										},
										"meta": {
											"$ref": "#/components/schemas/PageMeta"
										}
									},
									"required": ["data", "meta"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": [
					{
						"name": "cursor",
						"in": "query",
						"required": false,
						"description": "Opaque cursor from the previous page's meta.nextCursor.",
						"schema": {
							"type": "string",
							"minLength": 1
						}
					},
					{
						"name": "limit",
						"in": "query",
						"required": false,
						"description": "Page size, 1–100 (default 50).",
						"schema": {
							"type": "integer",
							"minimum": 1,
							"maximum": 100,
							"default": 50
						}
					},
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "listId",
						"required": true,
						"description": "The list's id."
					}
				]
			},
			"post": {
				"operationId": "addLeadsToList",
				"tags": ["Lists"],
				"summary": "Add people by profile URL",
				"description": "Up to 1000 per call. Each URL becomes a lead (or merges into the existing one) and joins the list. URLs that are not LinkedIn profiles come back in `invalid`; the rest are still added. For a CSV, send each row's profile URL and keep the other columns as fields.",
				"responses": {
					"200": {
						"description": "What was added",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "object",
											"properties": {
												"added": {
													"type": "integer",
													"description": "New members of the list."
												},
												"alreadyInList": {
													"type": "integer"
												},
												"invalid": {
													"type": "array",
													"items": {
														"type": "object",
														"properties": {
															"input": {
																"type": "string"
															},
															"reason": {
																"type": "string"
															}
														},
														"required": ["input", "reason"]
													},
													"description": "Entries that are not LinkedIn profiles; nothing was saved for them."
												},
												"leadIds": {
													"type": "array",
													"items": {
														"type": "string"
													},
													"description": "Every valid entry's lead id, in input order without repeats."
												}
											},
											"required": [
												"added",
												"alreadyInList",
												"invalid",
												"leadIds"
											]
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/AddLeadsToListInput"
							}
						}
					}
				},
				"parameters": [
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "listId",
						"required": true,
						"description": "The list's id."
					},
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			},
			"delete": {
				"operationId": "removeLeadsFromList",
				"tags": ["Lists"],
				"summary": "Remove leads from a list",
				"responses": {
					"200": {
						"description": "How many left the list",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "object",
											"properties": {
												"removed": {
													"type": "integer"
												}
											},
											"required": ["removed"]
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/RemoveLeadsFromListInput"
							}
						}
					}
				},
				"parameters": [
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "listId",
						"required": true,
						"description": "The list's id."
					},
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			}
		},
		"/v1/lists/{listId}/export": {
			"get": {
				"operationId": "exportListLeads",
				"tags": ["Lists"],
				"summary": "Export a list's leads as CSV",
				"description": "Every lead of the list as one CSV file (UTF-8 with a byte order mark, RFC 4180): the profile columns, `addedAt` (when it joined this list) and one `fields.<name>` column per custom field. A cell that would start with =, +, - or @ is prefixed with an apostrophe so spreadsheets never run it. The whole workspace, every list at once, is POST /v1/exports.",
				"responses": {
					"200": {
						"description": "The CSV file",
						"content": {
							"text/csv": {
								"schema": {
									"type": "string"
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": [
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "listId",
						"required": true,
						"description": "The list's id."
					}
				]
			}
		},
		"/v1/lists/{listId}/imports": {
			"post": {
				"operationId": "createImport",
				"tags": ["Imports"],
				"summary": "Import people into a list from LinkedIn",
				"description": "From a people search (filters or a pasted search URL) or from the people who reacted to or commented on a post. Runs in the background: the answer is the queued import; poll GET /v1/imports/{id} or wait for import.completed / import.failed. maxResults is capped at 1000. Blocklisted people are skipped. A sandbox sender only searches the simulated population.",
				"responses": {
					"200": {
						"description": "The queued import",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/Import"
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/CreateImportInput"
							}
						}
					}
				},
				"parameters": [
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "listId",
						"required": true,
						"description": "The list's id."
					},
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			},
			"get": {
				"operationId": "listImports",
				"tags": ["Imports"],
				"summary": "List a list's imports",
				"responses": {
					"200": {
						"description": "Newest first",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "array",
											"items": {
												"$ref": "#/components/schemas/Import"
											}
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": [
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "listId",
						"required": true,
						"description": "The list's id."
					}
				]
			}
		},
		"/v1/imports/{importId}": {
			"get": {
				"operationId": "getImport",
				"tags": ["Imports"],
				"summary": "Get an import's progress",
				"responses": {
					"200": {
						"description": "The import",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/Import"
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": [
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "importId",
						"required": true,
						"description": "The import's id."
					}
				]
			}
		},
		"/v1/search/people": {
			"post": {
				"operationId": "searchPeople",
				"tags": ["Search"],
				"summary": "Search LinkedIn people (nothing saved)",
				"description": "One page of results through a sender's account, to preview an audience before importing it. Give filters (ids from GET /v1/search/parameters) or a pasted LinkedIn / Sales Navigator search URL; pass meta.nextCursor back for the next page. A sandbox sender only searches the simulated population. LinkedIn's own search limits apply to real senders (429 when it rate-limits).",
				"responses": {
					"200": {
						"description": "A page of people",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "array",
											"items": {
												"$ref": "#/components/schemas/LinkedinPerson"
											}
										},
										"meta": {
											"allOf": [
												{
													"$ref": "#/components/schemas/PageMeta"
												},
												{
													"type": "object",
													"properties": {
														"total": {
															"type": "integer",
															"description": "LinkedIn's estimate of the total matches, when it gives one."
														}
													}
												}
											]
										}
									},
									"required": ["data", "meta"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/SearchPeopleInput"
							}
						}
					}
				},
				"parameters": [
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			}
		},
		"/v1/search/parameters": {
			"get": {
				"operationId": "searchParameters",
				"tags": ["Search"],
				"summary": "Look up ids for search filters",
				"description": "Locations, industries, companies and schools matching ?q=, with the ids filters take.",
				"responses": {
					"200": {
						"description": "Matches",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "array",
											"items": {
												"$ref": "#/components/schemas/SearchParameter"
											}
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": [
					{
						"name": "senderId",
						"in": "query",
						"required": true,
						"description": "The sender whose account looks it up.",
						"schema": {
							"type": "string"
						}
					},
					{
						"name": "type",
						"in": "query",
						"required": true,
						"description": "LOCATION, INDUSTRY, COMPANY or SCHOOL.",
						"schema": {
							"type": "string",
							"enum": ["LOCATION", "INDUSTRY", "COMPANY", "SCHOOL"]
						}
					},
					{
						"name": "q",
						"in": "query",
						"required": true,
						"description": "What to look up, e.g. \"Germany\" or \"Software Development\".",
						"schema": {
							"type": "string",
							"minLength": 1,
							"maxLength": 100
						}
					}
				]
			}
		},
		"/v1/blocklist": {
			"get": {
				"operationId": "listBlocklist",
				"tags": ["Blocklist"],
				"summary": "List the blocklist",
				"responses": {
					"200": {
						"description": "Every entry, newest first",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "array",
											"items": {
												"$ref": "#/components/schemas/BlocklistEntry"
											}
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": []
			},
			"post": {
				"operationId": "addBlocklistEntries",
				"tags": ["Blocklist"],
				"summary": "Block people or companies",
				"description": "Blocked people (by profile) and everyone at a blocked company (by current company name, case-insensitive) are never imported and never enrolled in a campaign. Entries already blocked are counted, not duplicated.",
				"responses": {
					"200": {
						"description": "What was added",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "object",
											"properties": {
												"added": {
													"type": "array",
													"items": {
														"$ref": "#/components/schemas/BlocklistEntry"
													}
												},
												"alreadyBlocked": {
													"type": "integer"
												},
												"invalid": {
													"type": "array",
													"items": {
														"type": "object",
														"properties": {
															"input": {
																"type": "string"
															},
															"reason": {
																"type": "string"
															}
														},
														"required": ["input", "reason"]
													}
												}
											},
											"required": ["added", "alreadyBlocked", "invalid"]
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/AddBlocklistEntriesInput"
							}
						}
					}
				},
				"parameters": [
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			}
		},
		"/v1/blocklist/{entryId}": {
			"delete": {
				"operationId": "deleteBlocklistEntry",
				"tags": ["Blocklist"],
				"summary": "Unblock",
				"responses": {
					"200": {
						"description": "Deleted",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "object",
											"properties": {
												"id": {
													"type": "string"
												},
												"deleted": {
													"type": "boolean",
													"enum": [true]
												}
											},
											"required": ["id", "deleted"]
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": [
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "entryId",
						"required": true,
						"description": "The entry's id."
					},
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			}
		},
		"/v1/campaigns": {
			"get": {
				"operationId": "listCampaigns",
				"tags": ["Campaigns"],
				"summary": "List campaigns",
				"description": "Newest first, each with its funnel (enrolled, invited, accepted, replied…). Archived campaigns only with ?status=archived.",
				"responses": {
					"200": {
						"description": "A page of campaigns",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "array",
											"items": {
												"$ref": "#/components/schemas/Campaign"
											}
										},
										"meta": {
											"$ref": "#/components/schemas/PageMeta"
										}
									},
									"required": ["data", "meta"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": [
					{
						"name": "status",
						"in": "query",
						"required": false,
						"description": "Only campaigns in this status. Without it archived ones are left out.",
						"schema": {
							"type": "string",
							"enum": ["draft", "running", "paused", "completed", "archived"]
						}
					},
					{
						"name": "cursor",
						"in": "query",
						"required": false,
						"schema": {
							"type": "string",
							"minLength": 1
						}
					},
					{
						"name": "limit",
						"in": "query",
						"required": false,
						"schema": {
							"type": "integer",
							"minimum": 1,
							"maximum": 100,
							"default": 50
						}
					}
				]
			},
			"post": {
				"operationId": "createCampaign",
				"tags": ["Campaigns"],
				"summary": "Create a campaign (draft)",
				"description": "A draft: nothing runs until POST /v1/campaigns/{id}/launch. The sequence is validated now (at most one invite, a message needs an invite before it unless audience is connected_only, templates must parse); senders and lists must belong to the workspace. Preview it before launching.",
				"responses": {
					"200": {
						"description": "The new draft",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/Campaign"
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/CreateCampaignInput"
							}
						}
					}
				},
				"parameters": [
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			}
		},
		"/v1/campaigns/{campaignId}": {
			"get": {
				"operationId": "getCampaign",
				"tags": ["Campaigns"],
				"summary": "Get a campaign",
				"responses": {
					"200": {
						"description": "The campaign with its funnel",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/Campaign"
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": [
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "campaignId",
						"required": true,
						"description": "The campaign's id."
					}
				]
			},
			"patch": {
				"operationId": "updateCampaign",
				"tags": ["Campaigns"],
				"summary": "Update a campaign",
				"description": "The name can change at any time. Steps, senders, lists and settings only while draft or paused (409 otherwise): pause a running campaign first. Live enrollments keep their sender and step number.",
				"responses": {
					"200": {
						"description": "The campaign",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/Campaign"
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"requestBody": {
					"required": false,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/UpdateCampaignInput"
							}
						}
					}
				},
				"parameters": [
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "campaignId",
						"required": true,
						"description": "The campaign's id."
					},
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			},
			"delete": {
				"operationId": "deleteCampaign",
				"tags": ["Campaigns"],
				"summary": "Delete a draft (or archive)",
				"description": "A draft is deleted. Any other campaign is archived instead: its live enrollments stop and its history stays.",
				"responses": {
					"200": {
						"description": "What happened",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "object",
											"properties": {
												"id": {
													"type": "string"
												},
												"deleted": {
													"type": "boolean",
													"description": "true for a draft (gone); false when it was archived instead."
												},
												"status": {
													"type": "string",
													"enum": [
														"draft",
														"running",
														"paused",
														"completed",
														"archived"
													]
												}
											},
											"required": ["id", "deleted"]
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": [
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "campaignId",
						"required": true,
						"description": "The campaign's id."
					},
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			}
		},
		"/v1/campaigns/{campaignId}/preview": {
			"post": {
				"operationId": "previewCampaign",
				"tags": ["Campaigns"],
				"summary": "Preview a campaign (saves nothing)",
				"description": "For every lead that would be enrolled (lists + leads added directly): the sender it would get (round-robin), every note and message exactly as it would be sent, and its issues — missing_variable, note_too_long (> 300), message_too_long (> 8000), blocklisted, already_in_campaign (live in another running or paused campaign), already_enrolled. A lead with any issue is skipped at launch. Campaign-level issues (no_senders, sender_not_active, no_steps, no_leads, plan_limit, live_campaign_limit) say whether the launch would be refused. Leads are paginated (?limit, default 25); totals cover every lead. Profile fields LinkedIn hasn't told us yet count as missing: give variables a fallback ({{firstName | \"there\"}}) or set fields.",
				"responses": {
					"200": {
						"description": "The preview",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/CampaignPreview"
										},
										"meta": {
											"$ref": "#/components/schemas/PageMeta"
										}
									},
									"required": ["data", "meta"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": [
					{
						"name": "cursor",
						"in": "query",
						"required": false,
						"schema": {
							"type": "string",
							"minLength": 1
						}
					},
					{
						"name": "limit",
						"in": "query",
						"required": false,
						"description": "Leads per page (default 25). Totals always cover every lead.",
						"schema": {
							"type": "integer",
							"minimum": 1,
							"maximum": 100,
							"default": 25
						}
					},
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "campaignId",
						"required": true,
						"description": "The campaign's id."
					},
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			}
		},
		"/v1/campaigns/{campaignId}/launch": {
			"post": {
				"operationId": "launchCampaign",
				"tags": ["Campaigns"],
				"summary": "Launch a draft",
				"description": "Starts sending for real (sandbox senders simulate). Refused with 422 and details.issues when a campaign-level issue blocks it. Every eligible lead is enrolled with a round-robin sender; leads with an issue are recorded as stopped enrollments with that stopReason; eligible leads over the plan's monthly enrollment cap wait and enroll automatically when it resets. Leads added to its lists later join within a few minutes.",
				"responses": {
					"200": {
						"description": "The running campaign and what was enrolled",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "object",
											"properties": {
												"campaign": {
													"$ref": "#/components/schemas/Campaign"
												},
												"enrolled": {
													"type": "integer"
												},
												"skipped": {
													"type": "integer",
													"description": "Leads with an issue (see preview), recorded as stopped enrollments with that stopReason."
												},
												"waitingForPlan": {
													"type": "integer",
													"description": "Eligible leads over the plan's monthly enrollment cap: not enrolled yet, they join automatically when the cap resets."
												}
											},
											"required": [
												"campaign",
												"enrolled",
												"skipped",
												"waitingForPlan"
											]
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": [
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "campaignId",
						"required": true,
						"description": "The campaign's id."
					},
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			}
		},
		"/v1/campaigns/{campaignId}/pause": {
			"post": {
				"operationId": "pauseCampaign",
				"tags": ["Campaigns"],
				"summary": "Pause a running campaign",
				"description": "Nothing more is sent; enrollments keep their place. Replies and acceptances are still recorded.",
				"responses": {
					"200": {
						"description": "The campaign",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/Campaign"
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": [
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "campaignId",
						"required": true,
						"description": "The campaign's id."
					},
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			}
		},
		"/v1/campaigns/{campaignId}/resume": {
			"post": {
				"operationId": "resumeCampaign",
				"tags": ["Campaigns"],
				"summary": "Resume a paused campaign",
				"description": "Actions that came due while paused run first, within each sender's limits.",
				"responses": {
					"200": {
						"description": "The campaign",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/Campaign"
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": [
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "campaignId",
						"required": true,
						"description": "The campaign's id."
					},
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			}
		},
		"/v1/campaigns/{campaignId}/archive": {
			"post": {
				"operationId": "archiveCampaign",
				"tags": ["Campaigns"],
				"summary": "Archive a campaign",
				"description": "Final. Live enrollments stop (stopReason campaign_archived); pending invitations are not withdrawn.",
				"responses": {
					"200": {
						"description": "The campaign",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/Campaign"
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": [
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "campaignId",
						"required": true,
						"description": "The campaign's id."
					},
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			}
		},
		"/v1/campaigns/{campaignId}/leads": {
			"post": {
				"operationId": "addCampaignLeads",
				"tags": ["Campaigns"],
				"summary": "Add leads straight to a campaign",
				"description": "Up to 100 leads, by leadId or profileUrl, each with its own fields — the way to personalise lead by lead ({{fields.opener}}). A profile URL the workspace doesn't know creates the lead. In a draft they enroll at launch; in a running or paused campaign they are enrolled now, through the same gates as launch. Re-adding a lead that was skipped checks it again.",
				"responses": {
					"200": {
						"description": "One result per lead",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "array",
											"items": {
												"$ref": "#/components/schemas/AddCampaignLeadResult"
											}
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/AddCampaignLeadsInput"
							}
						}
					}
				},
				"parameters": [
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "campaignId",
						"required": true,
						"description": "The campaign's id."
					},
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			}
		},
		"/v1/campaigns/{campaignId}/stats": {
			"get": {
				"operationId": "getCampaignStats",
				"tags": ["Campaigns"],
				"summary": "Campaign stats",
				"description": "Enrolled, active, invited, accepted (acceptance rate), messaged, replied (reply rate over contacted), completed, failed and stopped — in total, per step and per sender.",
				"responses": {
					"200": {
						"description": "The stats",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/CampaignStats"
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": [
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "campaignId",
						"required": true,
						"description": "The campaign's id."
					}
				]
			}
		},
		"/v1/campaigns/{campaignId}/enrollments": {
			"get": {
				"operationId": "listEnrollments",
				"tags": ["Enrollments"],
				"summary": "List a campaign's enrollments",
				"description": "Oldest first. Each says its status, step, next action time and, in plain English, why it is waiting (waitingReason).",
				"responses": {
					"200": {
						"description": "A page of enrollments",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "array",
											"items": {
												"$ref": "#/components/schemas/Enrollment"
											}
										},
										"meta": {
											"$ref": "#/components/schemas/PageMeta"
										}
									},
									"required": ["data", "meta"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": [
					{
						"name": "status",
						"in": "query",
						"required": false,
						"schema": {
							"type": "string",
							"enum": [
								"active",
								"waiting",
								"awaiting_acceptance",
								"completed",
								"replied",
								"stopped",
								"failed"
							]
						}
					},
					{
						"name": "cursor",
						"in": "query",
						"required": false,
						"schema": {
							"type": "string",
							"minLength": 1
						}
					},
					{
						"name": "limit",
						"in": "query",
						"required": false,
						"schema": {
							"type": "integer",
							"minimum": 1,
							"maximum": 100,
							"default": 50
						}
					},
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "campaignId",
						"required": true,
						"description": "The campaign's id."
					}
				]
			}
		},
		"/v1/campaigns/{campaignId}/enrollments/{enrollmentId}": {
			"get": {
				"operationId": "getEnrollment",
				"tags": ["Enrollments"],
				"summary": "Get an enrollment with its actions",
				"responses": {
					"200": {
						"description": "The enrollment and its action history",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/EnrollmentDetail"
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": [
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "campaignId",
						"required": true,
						"description": "The campaign's id."
					},
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "enrollmentId",
						"required": true,
						"description": "The enrollment's id."
					}
				]
			},
			"patch": {
				"operationId": "updateEnrollment",
				"tags": ["Enrollments"],
				"summary": "Set an enrollment's fields",
				"description": "Per-enrollment template fields, merged (\"\" removes a key). They override the lead's own fields in this campaign and apply to the notes and messages not sent yet.",
				"responses": {
					"200": {
						"description": "The enrollment",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/Enrollment"
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/UpdateEnrollmentInput"
							}
						}
					}
				},
				"parameters": [
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "campaignId",
						"required": true,
						"description": "The campaign's id."
					},
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "enrollmentId",
						"required": true,
						"description": "The enrollment's id."
					},
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			}
		},
		"/v1/campaigns/{campaignId}/enrollments/{enrollmentId}/stop": {
			"post": {
				"operationId": "stopEnrollment",
				"tags": ["Enrollments"],
				"summary": "Stop an enrollment",
				"description": "Final: its pending actions are cancelled (stopReason stopped_by_user). Only live enrollments (409 otherwise).",
				"responses": {
					"200": {
						"description": "The stopped enrollment",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/Enrollment"
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": [
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "campaignId",
						"required": true,
						"description": "The campaign's id."
					},
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "enrollmentId",
						"required": true,
						"description": "The enrollment's id."
					},
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			}
		},
		"/v1/conversations": {
			"get": {
				"operationId": "listConversations",
				"tags": ["Inbox"],
				"summary": "List conversations",
				"description": "Newest activity first, with the last message, the lead, the sender and the campaign behind it. Filter by senderId, leadId or unread=true.",
				"responses": {
					"200": {
						"description": "A page of conversations",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "array",
											"items": {
												"$ref": "#/components/schemas/Conversation"
											}
										},
										"meta": {
											"$ref": "#/components/schemas/PageMeta"
										}
									},
									"required": ["data", "meta"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": [
					{
						"name": "senderId",
						"in": "query",
						"required": false,
						"schema": {
							"type": "string"
						}
					},
					{
						"name": "leadId",
						"in": "query",
						"required": false,
						"schema": {
							"type": "string"
						}
					},
					{
						"name": "unread",
						"in": "query",
						"required": false,
						"description": "true: only conversations with unread inbound messages.",
						"schema": {
							"type": "string",
							"enum": ["true", "false"]
						}
					},
					{
						"name": "cursor",
						"in": "query",
						"required": false,
						"schema": {
							"type": "string",
							"minLength": 1
						}
					},
					{
						"name": "limit",
						"in": "query",
						"required": false,
						"schema": {
							"type": "integer",
							"minimum": 1,
							"maximum": 100,
							"default": 50
						}
					}
				]
			}
		},
		"/v1/conversations/{conversationId}": {
			"get": {
				"operationId": "getConversation",
				"tags": ["Inbox"],
				"summary": "Read a conversation",
				"description": "Every message, oldest first. Marks the conversation read.",
				"responses": {
					"200": {
						"description": "The conversation with its messages",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/ConversationDetail"
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"parameters": [
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "conversationId",
						"required": true,
						"description": "The conversation's id."
					}
				]
			}
		},
		"/v1/conversations/{conversationId}/messages": {
			"post": {
				"operationId": "sendConversationMessage",
				"tags": ["Inbox"],
				"summary": "Reply in a conversation",
				"description": "Sent on LinkedIn by the conversation's sender. Counts against its daily message cap: refused with 429 when the cap is reached and 409 when the sender is not active.",
				"responses": {
					"200": {
						"description": "The message as filed",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/Message"
										}
									},
									"required": ["data"]
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"402": {
						"$ref": "#/components/responses/PaymentRequired"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"409": {
						"$ref": "#/components/responses/Conflict"
					},
					"422": {
						"$ref": "#/components/responses/UnprocessableContent"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"503": {
						"$ref": "#/components/responses/ServiceUnavailable"
					}
				},
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/SendConversationMessageInput"
							}
						}
					}
				},
				"parameters": [
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "conversationId",
						"required": true,
						"description": "The conversation's id."
					},
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			}
		}
	},
	"components": {
		"schemas": {
			"User": {
				"type": "object",
				"properties": {
					"id": {
						"type": "string",
						"example": "user_V1StGXR8_Z5jdHi6B-myT"
					},
					"email": {
						"type": "string",
						"format": "email",
						"example": "ada@acme.com"
					},
					"name": {
						"type": "string",
						"example": "Ada Lovelace"
					},
					"createdAt": {
						"type": "string",
						"format": "date-time"
					},
					"updatedAt": {
						"type": "string",
						"format": "date-time"
					}
				},
				"required": ["id", "email", "name", "createdAt", "updatedAt"],
				"description": "Absent when the caller is an API key."
			},
			"SignUpInput": {
				"type": "object",
				"properties": {
					"email": {
						"type": "string",
						"maxLength": 320,
						"format": "email",
						"example": "ada@acme.com"
					},
					"name": {
						"type": "string",
						"minLength": 1,
						"maxLength": 120,
						"example": "Ada Lovelace"
					},
					"password": {
						"type": "string",
						"minLength": 10,
						"maxLength": 200,
						"description": "At least 10 characters."
					},
					"workspaceName": {
						"type": "string",
						"minLength": 1,
						"maxLength": 120,
						"description": "Defaults to the name's first word + \"'s workspace\"."
					}
				},
				"required": ["email", "name", "password"],
				"additionalProperties": false
			},
			"SignInInput": {
				"type": "object",
				"properties": {
					"email": {
						"type": "string",
						"format": "email"
					},
					"password": {
						"type": "string",
						"minLength": 1
					}
				},
				"required": ["email", "password"],
				"additionalProperties": false
			},
			"ConnectLink": {
				"type": "object",
				"properties": {
					"code": {
						"type": "string",
						"example": "7KQ2M9XH4P"
					},
					"workspaceName": {
						"type": "string",
						"example": "Acme"
					},
					"senderId": {
						"type": "string",
						"example": "snd_0yUkG9TD"
					},
					"senderName": {
						"type": "string",
						"description": "The sender's current name (\"LinkedIn account\" until LinkedIn reports the account's own)."
					},
					"mode": {
						"type": "string",
						"enum": ["connect", "reconnect"]
					},
					"status": {
						"type": "string",
						"enum": ["pending", "connected", "expired"]
					},
					"connectedAs": {
						"type": "string",
						"description": "The LinkedIn account's name, once connected.",
						"example": "Ada Lovelace"
					},
					"detail": {
						"type": "string",
						"description": "Why an expired link can't be used, when it is not just its age (e.g. the account is connected elsewhere)."
					},
					"expiresAt": {
						"type": "string",
						"format": "date-time"
					}
				},
				"required": [
					"code",
					"workspaceName",
					"senderId",
					"senderName",
					"mode",
					"status",
					"expiresAt"
				]
			},
			"DevSignInInput": {
				"type": "object",
				"properties": {
					"name": {
						"type": "string",
						"minLength": 1,
						"maxLength": 100,
						"description": "The simulated LinkedIn account's full name."
					}
				},
				"required": ["name"],
				"additionalProperties": false
			},
			"Workspace": {
				"type": "object",
				"properties": {
					"id": {
						"type": "string",
						"example": "org_Uakgb_J5m9g-0JDMbcJqL"
					},
					"name": {
						"type": "string",
						"example": "Acme"
					},
					"plan": {
						"type": "string",
						"enum": [
							"none",
							"starter",
							"growth",
							"scale",
							"tier_1",
							"tier_2",
							"tier_3",
							"tier_4"
						]
					},
					"planName": {
						"type": "string",
						"example": "Growth"
					},
					"limits": {
						"$ref": "#/components/schemas/PlanLimits"
					},
					"billing": {
						"$ref": "#/components/schemas/WorkspaceBilling"
					},
					"usage": {
						"$ref": "#/components/schemas/WorkspaceUsage"
					},
					"role": {
						"type": "string",
						"enum": ["owner", "member"],
						"description": "The caller's role; absent for API keys."
					},
					"createdAt": {
						"type": "string",
						"format": "date-time"
					}
				},
				"required": [
					"id",
					"name",
					"plan",
					"planName",
					"limits",
					"billing",
					"usage",
					"createdAt"
				]
			},
			"PlanLimits": {
				"type": "object",
				"properties": {
					"linkedinSenders": {
						"type": "integer",
						"description": "LinkedIn senders allowed now: the plan's included ones plus the extra accounts add-on."
					},
					"includedLinkedinSenders": {
						"type": "integer",
						"description": "LinkedIn senders the plan includes."
					},
					"extraLinkedinSenders": {
						"type": "integer",
						"description": "Extra LinkedIn accounts the workspace pays for monthly (AppSumo licences; 0 otherwise)."
					},
					"sandboxSenders": {
						"type": "integer"
					},
					"enrollmentsPerMonth": {
						"type": "integer"
					},
					"liveCampaigns": {
						"type": "integer",
						"description": "Absent when unlimited."
					}
				},
				"required": [
					"linkedinSenders",
					"includedLinkedinSenders",
					"extraLinkedinSenders",
					"sandboxSenders",
					"enrollmentsPerMonth"
				]
			},
			"WorkspaceBilling": {
				"type": "object",
				"properties": {
					"source": {
						"type": "string",
						"enum": ["subscription", "license", "comp", "none"],
						"description": "Where the plan comes from: a monthly `subscription` (Stripe), a lifetime `license` (AppSumo), a `comp` (complimentary) plan given by Outvoy, or `none` — the workspace has no plan and nothing that acts can be created until the owner starts the 7-day trial in the console (Settings → Billing)."
					},
					"status": {
						"type": "string",
						"enum": [
							"trialing",
							"active",
							"past_due",
							"canceled",
							"incomplete"
						],
						"description": "The subscription's status; only when `source` is `subscription`."
					},
					"trialEndsAt": {
						"type": "string",
						"format": "date-time",
						"description": "When the free trial ends and the first charge happens; only while trialing."
					},
					"renewsAt": {
						"type": "string",
						"format": "date-time",
						"description": "The next charge date; absent when the subscription is set to end (`cancelAtPeriodEnd`) or there is none."
					},
					"complimentaryUntil": {
						"type": "string",
						"format": "date-time",
						"description": "While `source` is `comp`: when the complimentary plan ends. Absent when it has no end date."
					}
				},
				"required": ["source"]
			},
			"WorkspaceUsage": {
				"type": "object",
				"properties": {
					"linkedinSenders": {
						"type": "integer"
					},
					"sandboxSenders": {
						"type": "integer"
					},
					"enrollmentsThisMonth": {
						"type": "integer"
					},
					"liveCampaigns": {
						"type": "integer"
					},
					"lists": {
						"type": "integer",
						"description": "Lists (audiences) in the workspace."
					},
					"launchedCampaigns": {
						"type": "integer",
						"description": "Campaigns ever launched, whatever their status now."
					},
					"unreadConversations": {
						"type": "integer",
						"description": "Conversations with an inbound message nobody has read yet (GET /v1/conversations?unread=true lists them; reading one marks it read)."
					}
				},
				"required": [
					"linkedinSenders",
					"sandboxSenders",
					"enrollmentsThisMonth",
					"liveCampaigns",
					"lists",
					"launchedCampaigns",
					"unreadConversations"
				]
			},
			"UpdateWorkspaceInput": {
				"type": "object",
				"properties": {
					"name": {
						"type": "string",
						"minLength": 1,
						"maxLength": 120
					}
				},
				"required": ["name"],
				"additionalProperties": false
			},
			"DeleteWorkspaceInput": {
				"type": "object",
				"properties": {
					"confirmName": {
						"type": "string",
						"minLength": 1,
						"maxLength": 120,
						"description": "The workspace's name, exactly as it is (GET /v1/me → workspace.name), to confirm.",
						"example": "Acme"
					}
				},
				"required": ["confirmName"],
				"additionalProperties": false
			},
			"ApiKey": {
				"type": "object",
				"properties": {
					"id": {
						"type": "string",
						"example": "key_2x4GmKq9Rk0bW1aP8sTnZ"
					},
					"name": {
						"type": "string",
						"example": "Claude Code"
					},
					"prefix": {
						"type": "string",
						"example": "ov_Jd8s"
					},
					"createdAt": {
						"type": "string",
						"format": "date-time"
					},
					"lastUsedAt": {
						"type": "string",
						"format": "date-time"
					},
					"revokedAt": {
						"type": "string",
						"format": "date-time"
					}
				},
				"required": ["id", "name", "prefix", "createdAt"]
			},
			"CreatedApiKey": {
				"allOf": [
					{
						"$ref": "#/components/schemas/ApiKey"
					},
					{
						"type": "object",
						"properties": {
							"secret": {
								"type": "string",
								"description": "The full key. Shown once: store it now.",
								"example": "ov_Jd8sKq2…"
							}
						},
						"required": ["secret"]
					}
				]
			},
			"CreateApiKeyInput": {
				"type": "object",
				"properties": {
					"name": {
						"type": "string",
						"minLength": 1,
						"maxLength": 80,
						"example": "Claude Code"
					}
				},
				"required": ["name"],
				"additionalProperties": false
			},
			"Event": {
				"type": "object",
				"properties": {
					"id": {
						"type": "string",
						"description": "Sortable: pass the last id you saw as ?after= to read on.",
						"example": "evt_01JB8Y2K7Q3W9E5R1T6Y4U0I2O"
					},
					"type": {
						"type": "string",
						"enum": [
							"sender.connected",
							"sender.needs_reconnect",
							"sender.paused",
							"sender.resumed",
							"import.completed",
							"import.failed",
							"campaign.launched",
							"campaign.paused",
							"campaign.resumed",
							"campaign.completed",
							"lead.enrolled",
							"lead.profile_visited",
							"lead.post_liked",
							"lead.invite_sent",
							"lead.invite_accepted",
							"lead.invite_withdrawn",
							"lead.message_sent",
							"lead.replied",
							"lead.completed",
							"lead.failed",
							"message.received",
							"campaign.archived",
							"lead.stopped",
							"lead.deleted",
							"lead.connected",
							"message.sent"
						]
					},
					"occurredAt": {
						"type": "string",
						"format": "date-time"
					},
					"data": {
						"type": "object",
						"additionalProperties": {},
						"description": "Ids plus the context needed to act without a second call (lead name and profile URL, campaign name, message text)."
					}
				},
				"required": ["id", "type", "occurredAt", "data"]
			},
			"PageMeta": {
				"type": "object",
				"properties": {
					"nextCursor": {
						"type": "string",
						"description": "Present when there is another page."
					}
				}
			},
			"WebhookEndpoint": {
				"type": "object",
				"properties": {
					"id": {
						"type": "string",
						"example": "whk_V1StGXR8_Z5jdHi6B-myT"
					},
					"url": {
						"type": "string",
						"format": "uri",
						"example": "https://example.com/outvoy"
					},
					"description": {
						"type": "string"
					},
					"eventTypes": {
						"type": "array",
						"items": {
							"type": "string",
							"enum": [
								"sender.connected",
								"sender.needs_reconnect",
								"sender.paused",
								"sender.resumed",
								"import.completed",
								"import.failed",
								"campaign.launched",
								"campaign.paused",
								"campaign.resumed",
								"campaign.completed",
								"lead.enrolled",
								"lead.profile_visited",
								"lead.post_liked",
								"lead.invite_sent",
								"lead.invite_accepted",
								"lead.invite_withdrawn",
								"lead.message_sent",
								"lead.replied",
								"lead.completed",
								"lead.failed",
								"message.received",
								"campaign.archived",
								"lead.stopped",
								"lead.deleted",
								"lead.connected",
								"message.sent"
							]
						},
						"description": "The event types sent to this endpoint. Empty means all."
					},
					"enabled": {
						"type": "boolean"
					},
					"disabledReason": {
						"type": "string",
						"description": "Why Outvoy disabled the endpoint (e.g. 50 consecutive failed deliveries). Re-enable it with PATCH enabled=true."
					},
					"consecutiveFailures": {
						"type": "integer"
					},
					"createdAt": {
						"type": "string",
						"format": "date-time"
					},
					"updatedAt": {
						"type": "string",
						"format": "date-time"
					}
				},
				"required": [
					"id",
					"url",
					"eventTypes",
					"enabled",
					"consecutiveFailures",
					"createdAt",
					"updatedAt"
				]
			},
			"WebhookEndpointWithSecret": {
				"allOf": [
					{
						"$ref": "#/components/schemas/WebhookEndpoint"
					},
					{
						"type": "object",
						"properties": {
							"secret": {
								"type": "string",
								"description": "The signing secret (whsec_…). Shown on creation and on rotate-secret only: store it now.",
								"example": "whsec_2b3c…"
							}
						},
						"required": ["secret"]
					}
				]
			},
			"CreateWebhookEndpointInput": {
				"type": "object",
				"properties": {
					"url": {
						"type": "string",
						"maxLength": 2048,
						"format": "uri",
						"description": "Where Outvoy POSTs events. HTTPS only (http://localhost is accepted outside production). Private and internal addresses are refused.",
						"example": "https://example.com/outvoy-webhook"
					},
					"description": {
						"type": "string",
						"maxLength": 500
					},
					"eventTypes": {
						"type": "array",
						"items": {
							"type": "string",
							"enum": [
								"sender.connected",
								"sender.needs_reconnect",
								"sender.paused",
								"sender.resumed",
								"import.completed",
								"import.failed",
								"campaign.launched",
								"campaign.paused",
								"campaign.resumed",
								"campaign.completed",
								"lead.enrolled",
								"lead.profile_visited",
								"lead.post_liked",
								"lead.invite_sent",
								"lead.invite_accepted",
								"lead.invite_withdrawn",
								"lead.message_sent",
								"lead.replied",
								"lead.completed",
								"lead.failed",
								"message.received",
								"campaign.archived",
								"lead.stopped",
								"lead.deleted",
								"lead.connected",
								"message.sent"
							]
						},
						"maxItems": 26,
						"default": [],
						"description": "Event types to receive, e.g. [\"lead.replied\"]. Empty or omitted means every event type."
					},
					"enabled": {
						"type": "boolean",
						"default": true
					}
				},
				"required": ["url"],
				"additionalProperties": false
			},
			"UpdateWebhookEndpointInput": {
				"type": "object",
				"properties": {
					"url": {
						"type": "string",
						"maxLength": 2048,
						"format": "uri",
						"description": "Where Outvoy POSTs events. HTTPS only (http://localhost is accepted outside production). Private and internal addresses are refused.",
						"example": "https://example.com/outvoy-webhook"
					},
					"description": {
						"type": "string",
						"maxLength": 500,
						"description": "An empty string clears it."
					},
					"eventTypes": {
						"type": "array",
						"items": {
							"type": "string",
							"enum": [
								"sender.connected",
								"sender.needs_reconnect",
								"sender.paused",
								"sender.resumed",
								"import.completed",
								"import.failed",
								"campaign.launched",
								"campaign.paused",
								"campaign.resumed",
								"campaign.completed",
								"lead.enrolled",
								"lead.profile_visited",
								"lead.post_liked",
								"lead.invite_sent",
								"lead.invite_accepted",
								"lead.invite_withdrawn",
								"lead.message_sent",
								"lead.replied",
								"lead.completed",
								"lead.failed",
								"message.received",
								"campaign.archived",
								"lead.stopped",
								"lead.deleted",
								"lead.connected",
								"message.sent"
							]
						},
						"maxItems": 26,
						"description": "Event types to receive, e.g. [\"lead.replied\"]. Empty or omitted means every event type."
					},
					"enabled": {
						"type": "boolean",
						"description": "false stops deliveries; true re-enables an endpoint (also one Outvoy disabled after repeated failures) and resets its failure count."
					}
				},
				"additionalProperties": false
			},
			"WebhookDelivery": {
				"type": "object",
				"properties": {
					"id": {
						"type": "string",
						"example": "whd_3nV8p0qLw2xYz7AbCdEfG"
					},
					"endpointId": {
						"type": "string"
					},
					"eventId": {
						"type": "string",
						"description": "The event delivered (its Outvoy-Event-Id header). Test pings have their own evt_test_… id."
					},
					"eventType": {
						"type": "string",
						"description": "A public event type, or webhook.test for a test ping.",
						"example": "lead.replied"
					},
					"attempt": {
						"type": "integer",
						"description": "1 to 8."
					},
					"status": {
						"type": "string",
						"enum": ["pending", "succeeded", "failed"]
					},
					"responseStatus": {
						"type": "integer"
					},
					"responseBody": {
						"type": "string",
						"description": "The first 2 KB of the endpoint's answer."
					},
					"error": {
						"type": "string",
						"description": "Timeout or network error, when there was no response."
					},
					"durationMs": {
						"type": "integer"
					},
					"nextAttemptAt": {
						"type": "string",
						"format": "date-time",
						"description": "Pending: when it will be attempted. Failed: when the retry is scheduled (absent after the last attempt)."
					},
					"createdAt": {
						"type": "string",
						"format": "date-time"
					},
					"attemptedAt": {
						"type": "string",
						"format": "date-time"
					}
				},
				"required": [
					"id",
					"endpointId",
					"eventId",
					"eventType",
					"attempt",
					"status",
					"createdAt"
				]
			},
			"License": {
				"type": "object",
				"properties": {
					"id": {
						"type": "string",
						"example": "lic_k3Jd9sLq0Wm2Xn4Bv6Cz8"
					},
					"provider": {
						"type": "string",
						"enum": ["appsumo"]
					},
					"licenseKey": {
						"type": "string",
						"description": "The provider's licence key (AppSumo: a UUID)."
					},
					"plan": {
						"type": "string",
						"enum": [
							"none",
							"starter",
							"growth",
							"scale",
							"tier_1",
							"tier_2",
							"tier_3",
							"tier_4"
						],
						"description": "The plan this licence gives; absent until AppSumo tells us the tier."
					},
					"status": {
						"type": "string",
						"enum": ["pending", "active", "replaced", "deactivated"]
					},
					"activatedAt": {
						"type": "string",
						"format": "date-time"
					},
					"deactivatedAt": {
						"type": "string",
						"format": "date-time"
					},
					"createdAt": {
						"type": "string",
						"format": "date-time"
					},
					"updatedAt": {
						"type": "string",
						"format": "date-time"
					}
				},
				"required": [
					"id",
					"provider",
					"licenseKey",
					"status",
					"createdAt",
					"updatedAt"
				]
			},
			"RedeemLicenseInput": {
				"type": "object",
				"properties": {
					"token": {
						"type": "string",
						"minLength": 1,
						"maxLength": 200,
						"description": "The one-time token from the console's /redeem?license=… link after AppSumo's redirect."
					}
				},
				"required": ["token"],
				"additionalProperties": false
			},
			"Billing": {
				"type": "object",
				"properties": {
					"plan": {
						"type": "string",
						"enum": [
							"none",
							"starter",
							"growth",
							"scale",
							"tier_1",
							"tier_2",
							"tier_3",
							"tier_4"
						]
					},
					"planName": {
						"type": "string",
						"example": "Growth"
					},
					"source": {
						"type": "string",
						"enum": ["subscription", "license", "comp", "none"]
					},
					"status": {
						"type": "string",
						"enum": [
							"trialing",
							"active",
							"past_due",
							"canceled",
							"incomplete"
						],
						"description": "Only when `source` is `subscription`."
					},
					"trialEndsAt": {
						"type": "string",
						"format": "date-time"
					},
					"renewsAt": {
						"type": "string",
						"format": "date-time",
						"description": "The next charge date (the trial's end while trialing)."
					},
					"cancelAtPeriodEnd": {
						"type": "boolean",
						"description": "The subscription ends at `endsAt` instead of renewing."
					},
					"endsAt": {
						"type": "string",
						"format": "date-time",
						"description": "When a subscription set to cancel stops giving its plan."
					},
					"graceEndsAt": {
						"type": "string",
						"format": "date-time",
						"description": "While `past_due`: the plan stays until then, unless the payment method is updated and the charge succeeds."
					},
					"priceUsdPerMonth": {
						"type": "number",
						"description": "The subscription's monthly price after the trial."
					},
					"complimentaryUntil": {
						"type": "string",
						"format": "date-time",
						"description": "While `source` is `comp`: when the complimentary plan ends (nothing is charged then; the workspace falls back to what it pays for, or to no plan). Absent when it has no end date."
					},
					"trialEligible": {
						"type": "boolean",
						"description": "A first subscription starts with the 7-day free trial; a workspace that already had one subscribes without it."
					},
					"checkoutAvailable": {
						"type": "boolean",
						"description": "Whether this server can start a checkout (Stripe configured, or the local simulator)."
					},
					"simulated": {
						"type": "boolean",
						"description": "Development only: checkout and portal are simulated, no money moves."
					},
					"extraSenders": {
						"$ref": "#/components/schemas/ExtraSendersBilling"
					}
				},
				"required": [
					"plan",
					"planName",
					"source",
					"cancelAtPeriodEnd",
					"trialEligible",
					"checkoutAvailable",
					"simulated",
					"extraSenders"
				]
			},
			"ExtraSendersBilling": {
				"type": "object",
				"properties": {
					"offered": {
						"type": "boolean",
						"description": "Whether this workspace can buy extra LinkedIn accounts: AppSumo lifetime licences only (a monthly plan grows by moving to a bigger plan)."
					},
					"available": {
						"type": "boolean",
						"description": "Whether this server can sell it (Stripe with `STRIPE_PRICE_EXTRA_SENDER`, or the local simulator)."
					},
					"priceUsdPerMonth": {
						"type": "number",
						"description": "What one extra LinkedIn account costs a month."
					},
					"included": {
						"type": "integer",
						"description": "LinkedIn senders the plan includes (1 on every AppSumo tier)."
					},
					"quantity": {
						"type": "integer",
						"description": "Extra LinkedIn accounts the workspace pays for now."
					},
					"connected": {
						"type": "integer",
						"description": "LinkedIn senders connected now (paused ones included; disconnected ones don't count). The add-on can't go below `connected - included`."
					},
					"max": {
						"type": "integer",
						"description": "The most extra accounts one workspace can buy."
					},
					"status": {
						"type": "string",
						"enum": [
							"trialing",
							"active",
							"past_due",
							"canceled",
							"incomplete"
						],
						"description": "The add-on subscription's status, once there is one."
					},
					"renewsAt": {
						"type": "string",
						"format": "date-time"
					},
					"endsAt": {
						"type": "string",
						"format": "date-time",
						"description": "When a cancelled add-on stops: its extra accounts stay until then."
					},
					"graceEndsAt": {
						"type": "string",
						"format": "date-time",
						"description": "While `past_due`: the extra accounts stay until then, then the newest LinkedIn senders beyond the allowance are paused."
					}
				},
				"required": [
					"offered",
					"available",
					"priceUsdPerMonth",
					"included",
					"quantity",
					"connected",
					"max"
				]
			},
			"StartCheckoutInput": {
				"type": "object",
				"properties": {
					"plan": {
						"type": "string",
						"enum": ["starter", "growth", "scale"],
						"description": "The monthly plan to subscribe to. A first subscription starts with a 7-day free trial; the card is charged on day 8 unless it is cancelled."
					}
				},
				"required": ["plan"],
				"additionalProperties": false
			},
			"SetExtraSendersInput": {
				"type": "object",
				"properties": {
					"quantity": {
						"type": "integer",
						"minimum": 0,
						"maximum": 50,
						"description": "Extra LinkedIn accounts to pay for, on top of the one the lifetime licence includes ($19/month each). `0` cancels the add-on at the end of its paid period. Fewer than the LinkedIn senders connected beyond the included one is refused: disconnect senders first."
					}
				},
				"required": ["quantity"],
				"additionalProperties": false
			},
			"SupportIdentity": {
				"type": "object",
				"properties": {
					"data": {
						"type": "object",
						"properties": {
							"email": {
								"type": "string",
								"format": "email",
								"example": "ada@acme.com"
							},
							"emailSignature": {
								"type": "string",
								"description": "HMAC-SHA256 (hex) of the email with the support chat's identity secret, so the chat can trust the address. Absent when verification is not configured."
							},
							"sessionToken": {
								"type": "string",
								"description": "A stable, unguessable token for this user's chat session, so their conversation history follows them across browsers. Absent when verification is not configured."
							}
						},
						"required": ["email"]
					}
				},
				"required": ["data"]
			},
			"DataExport": {
				"type": "object",
				"properties": {
					"id": {
						"type": "string",
						"example": "exp_9fKq2LmZ0aB4cD6eF8gH1"
					},
					"status": {
						"type": "string",
						"enum": ["queued", "running", "ready", "failed", "expired"]
					},
					"requestedBy": {
						"type": "string",
						"description": "The user who asked for it (always a workspace owner)."
					},
					"sizeBytes": {
						"type": "integer",
						"description": "The archive's size; once ready."
					},
					"records": {
						"type": "object",
						"additionalProperties": {
							"type": "integer"
						},
						"description": "How many records each file of the archive holds, by file name (README.json lists them with a description); once ready.",
						"example": {
							"leads.json": 1240,
							"messages.json": 318
						}
					},
					"error": {
						"type": "string",
						"description": "Why it failed; only when `failed`."
					},
					"createdAt": {
						"type": "string",
						"format": "date-time"
					},
					"startedAt": {
						"type": "string",
						"format": "date-time"
					},
					"finishedAt": {
						"type": "string",
						"format": "date-time"
					},
					"expiresAt": {
						"type": "string",
						"format": "date-time",
						"description": "When the archive is deleted (7 days after it was built); once ready."
					},
					"downloadUrl": {
						"type": "string",
						"format": "uri",
						"description": "A signed link to the ZIP archive, valid for 15 minutes from this response; only when `ready`. It needs no Authorization header, so a browser can open it — treat it like a password and don't share it. Read the export again for a fresh link."
					},
					"downloadUrlExpiresAt": {
						"type": "string",
						"format": "date-time",
						"description": "When `downloadUrl` stops working."
					}
				},
				"required": ["id", "status", "requestedBy", "createdAt"]
			},
			"Sender": {
				"type": "object",
				"properties": {
					"id": {
						"type": "string",
						"example": "snd_8hJ2kLm0PqRsT4uVwXyZa"
					},
					"kind": {
						"type": "string",
						"enum": ["linkedin", "sandbox"]
					},
					"status": {
						"type": "string",
						"enum": [
							"connecting",
							"active",
							"paused",
							"needs_reconnect",
							"restricted",
							"disconnected"
						]
					},
					"name": {
						"type": "string",
						"example": "Ada Lovelace"
					},
					"profileUrl": {
						"type": "string",
						"format": "uri",
						"example": "https://www.linkedin.com/in/ada-lovelace"
					},
					"avatarUrl": {
						"type": "string",
						"format": "uri"
					},
					"headline": {
						"type": "string"
					},
					"statusDetail": {
						"type": "string",
						"description": "Why the sender is in its status, in plain English."
					},
					"pausedUntil": {
						"type": "string",
						"format": "date-time",
						"description": "Set when the engine paused the sender after a LinkedIn limit; it resumes on its own then."
					},
					"limits": {
						"$ref": "#/components/schemas/SenderLimits"
					},
					"effectiveLimits": {
						"allOf": [
							{
								"$ref": "#/components/schemas/SenderLimits"
							},
							{
								"description": "The limits in force today, warm-up applied."
							}
						]
					},
					"schedule": {
						"$ref": "#/components/schemas/SenderSchedule"
					},
					"warmup": {
						"$ref": "#/components/schemas/SenderWarmup"
					},
					"usage": {
						"$ref": "#/components/schemas/SenderUsage"
					},
					"connectedAt": {
						"type": "string",
						"format": "date-time"
					},
					"accountManagedExternally": {
						"type": "boolean",
						"enum": [true],
						"description": "Present when the LinkedIn account was attached by Outvoy from an account managed elsewhere: disconnecting this sender keeps the account and its session at the provider."
					},
					"createdAt": {
						"type": "string",
						"format": "date-time"
					},
					"updatedAt": {
						"type": "string",
						"format": "date-time"
					}
				},
				"required": [
					"id",
					"kind",
					"status",
					"name",
					"limits",
					"effectiveLimits",
					"schedule",
					"warmup",
					"usage",
					"createdAt",
					"updatedAt"
				]
			},
			"SenderLimits": {
				"type": "object",
				"properties": {
					"dailyInvites": {
						"type": "integer",
						"minimum": 0,
						"maximum": 40
					},
					"weeklyInvites": {
						"type": "integer",
						"minimum": 0,
						"maximum": 200
					},
					"dailyMessages": {
						"type": "integer",
						"minimum": 0,
						"maximum": 150
					},
					"dailyProfileViews": {
						"type": "integer",
						"minimum": 0,
						"maximum": 150
					},
					"dailyPostLikes": {
						"type": "integer",
						"minimum": 0,
						"maximum": 100
					}
				},
				"required": [
					"dailyInvites",
					"weeklyInvites",
					"dailyMessages",
					"dailyProfileViews",
					"dailyPostLikes"
				],
				"additionalProperties": false,
				"description": "Per-sender caps. Defaults: 20 invites/day, 100/week, 50 messages/day, 60 profile views/day, 30 post likes/day. Ceilings: 40, 200, 150, 150, 100."
			},
			"SenderSchedule": {
				"type": "object",
				"properties": {
					"timezone": {
						"type": "string",
						"example": "Europe/Madrid"
					},
					"days": {
						"type": "array",
						"items": {
							"type": "integer",
							"minimum": 1,
							"maximum": 7
						},
						"minItems": 1,
						"maxItems": 7
					},
					"start": {
						"type": "string",
						"pattern": "^([01]\\d|2[0-3]):[0-5]\\d$",
						"example": "09:00"
					},
					"end": {
						"type": "string",
						"pattern": "^([01]\\d|2[0-3]):[0-5]\\d$",
						"example": "18:00"
					}
				},
				"required": ["timezone", "days", "start", "end"],
				"additionalProperties": false,
				"description": "Working hours: the sender only acts on these weekdays (1 = Monday) between start and end, in its timezone."
			},
			"SenderWarmup": {
				"type": "object",
				"properties": {
					"enabled": {
						"type": "boolean"
					},
					"startPercent": {
						"type": "integer",
						"minimum": 10,
						"maximum": 100
					},
					"durationDays": {
						"type": "integer",
						"minimum": 1,
						"maximum": 60
					},
					"startedAt": {
						"type": "string",
						"format": "date-time",
						"example": "2026-10-28T09:00:00.000Z"
					}
				},
				"required": ["enabled", "startPercent", "durationDays", "startedAt"],
				"description": "A new sender starts at startPercent of its limits and ramps linearly to 100% over durationDays."
			},
			"SenderUsage": {
				"type": "object",
				"properties": {
					"invitesToday": {
						"type": "integer"
					},
					"invitesThisWeek": {
						"type": "integer"
					},
					"messagesToday": {
						"type": "integer"
					},
					"profileViewsToday": {
						"type": "integer"
					},
					"postLikesToday": {
						"type": "integer"
					}
				},
				"required": [
					"invitesToday",
					"invitesThisWeek",
					"messagesToday",
					"profileViewsToday",
					"postLikesToday"
				]
			},
			"CreateSenderConnectLinkInput": {
				"type": "object",
				"properties": {
					"name": {
						"type": "string",
						"minLength": 1,
						"maxLength": 200,
						"description": "A label until LinkedIn reports the account's own name (default \"LinkedIn account\")."
					},
					"reconnectSenderId": {
						"type": "string",
						"description": "Reconnect this existing sender (status needs_reconnect, or any connected one) instead of adding a new one. Does not count against the plan again."
					}
				},
				"additionalProperties": false
			},
			"CreateSandboxSenderInput": {
				"type": "object",
				"properties": {
					"name": {
						"type": "string",
						"minLength": 1,
						"maxLength": 200,
						"description": "Defaults to a generated persona's name."
					}
				},
				"additionalProperties": false
			},
			"UpdateSenderInput": {
				"type": "object",
				"properties": {
					"name": {
						"type": "string",
						"minLength": 1,
						"maxLength": 200
					},
					"limits": {
						"type": "object",
						"properties": {
							"dailyInvites": {
								"type": "integer",
								"minimum": 0,
								"maximum": 40
							},
							"weeklyInvites": {
								"type": "integer",
								"minimum": 0,
								"maximum": 200
							},
							"dailyMessages": {
								"type": "integer",
								"minimum": 0,
								"maximum": 150
							},
							"dailyProfileViews": {
								"type": "integer",
								"minimum": 0,
								"maximum": 150
							},
							"dailyPostLikes": {
								"type": "integer",
								"minimum": 0,
								"maximum": 100
							}
						},
						"additionalProperties": false,
						"description": "Any subset of the caps; the rest keep their value. Hard ceilings: 40 invites/day, 200/week, 150 messages/day, 150 profile views/day, 100 post likes/day."
					},
					"schedule": {
						"$ref": "#/components/schemas/SenderSchedule"
					},
					"warmupEnabled": {
						"type": "boolean",
						"description": "Warm-up starts a new sender at 30% of its limits and ramps to 100% over 14 days."
					}
				},
				"additionalProperties": false
			},
			"Lead": {
				"type": "object",
				"properties": {
					"id": {
						"type": "string",
						"example": "lead_Qw3rTy7uIo9pAs1dFg2hJ"
					},
					"profileUrl": {
						"type": "string",
						"format": "uri",
						"example": "https://www.linkedin.com/in/jane-doe"
					},
					"publicIdentifier": {
						"type": "string",
						"example": "jane-doe"
					},
					"providerId": {
						"type": "string",
						"description": "LinkedIn's member id, once known.",
						"example": "ACoAAB1x2y3z"
					},
					"firstName": {
						"type": "string"
					},
					"lastName": {
						"type": "string"
					},
					"fullName": {
						"type": "string"
					},
					"headline": {
						"type": "string"
					},
					"title": {
						"type": "string"
					},
					"company": {
						"type": "string"
					},
					"location": {
						"type": "string"
					},
					"avatarUrl": {
						"type": "string",
						"format": "uri"
					},
					"fields": {
						"$ref": "#/components/schemas/LeadFields"
					},
					"source": {
						"type": "string",
						"enum": [
							"search",
							"profile_url",
							"post_engagement",
							"api",
							"inbound"
						]
					},
					"createdAt": {
						"type": "string",
						"format": "date-time"
					},
					"updatedAt": {
						"type": "string",
						"format": "date-time"
					}
				},
				"required": [
					"id",
					"profileUrl",
					"fields",
					"source",
					"createdAt",
					"updatedAt"
				]
			},
			"LeadFields": {
				"type": "object",
				"additionalProperties": {
					"type": "string",
					"maxLength": 2000
				},
				"description": "Per-enrollment template fields; they override the lead's own fields with the same name."
			},
			"UpdateLeadInput": {
				"type": "object",
				"properties": {
					"fields": {
						"$ref": "#/components/schemas/LeadFields"
					}
				},
				"required": ["fields"],
				"additionalProperties": false
			},
			"DeletedLead": {
				"type": "object",
				"properties": {
					"id": {
						"type": "string"
					},
					"deleted": {
						"type": "boolean",
						"enum": [true]
					},
					"blocklisted": {
						"type": "boolean",
						"description": "true when `blocklist` was asked for: the person's profile is on the workspace blocklist now (added, or already there)."
					},
					"enrollmentsStopped": {
						"type": "integer",
						"description": "Live enrollments stopped before deletion: nothing queued for the person runs afterwards."
					},
					"enrollmentsDeleted": {
						"type": "integer"
					},
					"conversationsDeleted": {
						"type": "integer"
					},
					"eventsRedacted": {
						"type": "integer",
						"description": "Public events (and their webhook deliveries) that named the person: their personal fields were blanked, ids kept."
					},
					"exportsExpired": {
						"type": "integer",
						"description": "Ready workspace exports deleted because they contained the person. Request a new one if you need it."
					}
				},
				"required": [
					"id",
					"deleted",
					"blocklisted",
					"enrollmentsStopped",
					"enrollmentsDeleted",
					"conversationsDeleted",
					"eventsRedacted",
					"exportsExpired"
				]
			},
			"DeleteLeadInput": {
				"type": "object",
				"properties": {
					"blocklist": {
						"type": "boolean",
						"default": true,
						"description": "Also add the person's LinkedIn profile to the workspace blocklist (default true), so no import, list or campaign brings them back. The blocklist keeps the profile identifier itself: it is the suppression list that honours their request."
					}
				},
				"additionalProperties": false
			},
			"List": {
				"type": "object",
				"properties": {
					"id": {
						"type": "string",
						"example": "list_Zx8cVb6nM4qW2eR0tY1uI"
					},
					"name": {
						"type": "string",
						"example": "Heads of RevOps · DACH"
					},
					"description": {
						"type": "string"
					},
					"leadCount": {
						"type": "integer"
					},
					"createdAt": {
						"type": "string",
						"format": "date-time"
					},
					"updatedAt": {
						"type": "string",
						"format": "date-time"
					}
				},
				"required": ["id", "name", "leadCount", "createdAt", "updatedAt"]
			},
			"CreateListInput": {
				"type": "object",
				"properties": {
					"name": {
						"type": "string",
						"minLength": 1,
						"maxLength": 120,
						"example": "Heads of RevOps · DACH"
					},
					"description": {
						"type": "string",
						"maxLength": 2000
					}
				},
				"required": ["name"],
				"additionalProperties": false
			},
			"UpdateListInput": {
				"type": "object",
				"properties": {
					"name": {
						"type": "string",
						"minLength": 1,
						"maxLength": 120
					},
					"description": {
						"type": "string",
						"maxLength": 2000,
						"description": "\"\" clears it."
					}
				},
				"additionalProperties": false
			},
			"AddLeadsToListInput": {
				"type": "object",
				"properties": {
					"leads": {
						"type": "array",
						"items": {
							"$ref": "#/components/schemas/LeadToAdd"
						},
						"minItems": 1,
						"maxItems": 1000,
						"description": "Up to 1000 people by profile URL. A person already in the workspace is merged (names you send win, fields are merged), never duplicated. CSV files: send each row's profile URL plus its other columns as fields."
					}
				},
				"required": ["leads"],
				"additionalProperties": false
			},
			"LeadToAdd": {
				"type": "object",
				"properties": {
					"profileUrl": {
						"type": "string",
						"minLength": 1,
						"maxLength": 2000,
						"description": "A LinkedIn profile URL (linkedin.com/in/…, or a Sales Navigator lead URL) or a bare identifier.",
						"example": "https://www.linkedin.com/in/jane-doe"
					},
					"fields": {
						"$ref": "#/components/schemas/LeadFields"
					},
					"firstName": {
						"type": "string",
						"maxLength": 200
					},
					"lastName": {
						"type": "string",
						"maxLength": 200
					},
					"company": {
						"type": "string",
						"maxLength": 200
					},
					"title": {
						"type": "string",
						"maxLength": 200
					}
				},
				"required": ["profileUrl"],
				"additionalProperties": false
			},
			"RemoveLeadsFromListInput": {
				"type": "object",
				"properties": {
					"leadIds": {
						"type": "array",
						"items": {
							"type": "string"
						},
						"minItems": 1,
						"maxItems": 1000,
						"description": "The leads leave the list; they stay in the workspace."
					}
				},
				"required": ["leadIds"],
				"additionalProperties": false
			},
			"Import": {
				"type": "object",
				"properties": {
					"id": {
						"type": "string",
						"example": "imp_Bv7nQ2xR9tLk0sWe3yUi1"
					},
					"listId": {
						"type": "string"
					},
					"senderId": {
						"type": "string",
						"description": "The sender whose LinkedIn account runs the search."
					},
					"source": {
						"$ref": "#/components/schemas/ImportSource"
					},
					"status": {
						"type": "string",
						"enum": ["queued", "running", "completed", "failed"]
					},
					"found": {
						"type": "integer",
						"description": "People read from LinkedIn so far (at most maxResults)."
					},
					"imported": {
						"type": "integer",
						"description": "People added to the list."
					},
					"skipped": {
						"type": "integer",
						"description": "Blocklisted, already in the list, or without a usable profile."
					},
					"error": {
						"type": "string",
						"description": "Why it failed, when status is failed."
					},
					"startedAt": {
						"type": "string",
						"format": "date-time"
					},
					"finishedAt": {
						"type": "string",
						"format": "date-time"
					},
					"createdAt": {
						"type": "string",
						"format": "date-time"
					},
					"updatedAt": {
						"type": "string",
						"format": "date-time"
					}
				},
				"required": [
					"id",
					"listId",
					"senderId",
					"source",
					"status",
					"found",
					"imported",
					"skipped",
					"createdAt",
					"updatedAt"
				]
			},
			"ImportSource": {
				"oneOf": [
					{
						"type": "object",
						"properties": {
							"type": {
								"type": "string",
								"enum": ["search"]
							},
							"url": {
								"type": "string"
							},
							"filters": {
								"$ref": "#/components/schemas/PeopleSearchFilters"
							},
							"maxResults": {
								"type": "integer"
							}
						},
						"required": ["type", "maxResults"]
					},
					{
						"type": "object",
						"properties": {
							"type": {
								"type": "string",
								"enum": ["post_engagers"]
							},
							"postUrl": {
								"type": "string"
							},
							"include": {
								"type": "array",
								"items": {
									"type": "string",
									"enum": ["reactions", "comments"]
								}
							},
							"maxResults": {
								"type": "integer"
							}
						},
						"required": ["type", "postUrl", "include", "maxResults"]
					}
				]
			},
			"PeopleSearchFilters": {
				"type": "object",
				"properties": {
					"keywords": {
						"type": "string",
						"minLength": 1,
						"maxLength": 200,
						"description": "Free text LinkedIn matches against names, titles, companies.",
						"example": "head of revops saas"
					},
					"title": {
						"type": "string",
						"minLength": 1,
						"maxLength": 200,
						"description": "Current job title, free text.",
						"example": "Head of RevOps"
					},
					"locationIds": {
						"type": "array",
						"items": {
							"type": "string",
							"minLength": 1,
							"maxLength": 64
						},
						"maxItems": 25,
						"default": [],
						"description": "Ids from GET /v1/search/parameters?type=LOCATION."
					},
					"industryIds": {
						"type": "array",
						"items": {
							"type": "string",
							"minLength": 1,
							"maxLength": 64
						},
						"maxItems": 25,
						"default": [],
						"description": "Ids from GET /v1/search/parameters?type=INDUSTRY."
					},
					"companyIds": {
						"type": "array",
						"items": {
							"type": "string",
							"minLength": 1,
							"maxLength": 64
						},
						"maxItems": 25,
						"default": [],
						"description": "Current company ids from GET /v1/search/parameters?type=COMPANY."
					},
					"networkDistance": {
						"type": "array",
						"items": {
							"anyOf": [
								{
									"type": "number",
									"enum": [1]
								},
								{
									"type": "number",
									"enum": [2]
								},
								{
									"type": "number",
									"enum": [3]
								}
							]
						},
						"maxItems": 3,
						"default": [],
						"description": "1 = 1st-degree connections, 2 = 2nd, 3 = 3rd and beyond."
					}
				},
				"additionalProperties": false
			},
			"CreateImportInput": {
				"type": "object",
				"properties": {
					"senderId": {
						"type": "string",
						"description": "The sender whose LinkedIn account runs the search. A sandbox sender only searches the simulated population."
					},
					"source": {
						"$ref": "#/components/schemas/ImportSourceInput"
					}
				},
				"required": ["senderId", "source"],
				"additionalProperties": false
			},
			"ImportSourceInput": {
				"oneOf": [
					{
						"type": "object",
						"properties": {
							"type": {
								"type": "string",
								"enum": ["search"]
							},
							"url": {
								"type": "string",
								"maxLength": 4000,
								"format": "uri",
								"example": "https://www.linkedin.com/search/results/people/?keywords=head%20of%20revops",
								"description": "A pasted LinkedIn or Sales Navigator people-search URL. Give url or filters, not both."
							},
							"filters": {
								"$ref": "#/components/schemas/PeopleSearchFilters"
							},
							"maxResults": {
								"type": "integer",
								"minimum": 1,
								"maximum": 1000,
								"default": 250,
								"description": "How many people to read at most. Capped at 1000; default 250."
							}
						},
						"required": ["type"],
						"additionalProperties": false
					},
					{
						"type": "object",
						"properties": {
							"type": {
								"type": "string",
								"enum": ["post_engagers"]
							},
							"postUrl": {
								"type": "string",
								"maxLength": 2000,
								"format": "uri",
								"description": "The post's URL (linkedin.com/posts/…-activity-<id>-…, /feed/update/urn:li:activity:<id>, ugcPost or share URLs)."
							},
							"include": {
								"type": "array",
								"items": {
									"type": "string",
									"enum": ["reactions", "comments"]
								},
								"minItems": 1,
								"maxItems": 2,
								"default": ["reactions", "comments"],
								"description": "Who to import: reactions, comments or both (default both)."
							},
							"maxResults": {
								"type": "integer",
								"minimum": 1,
								"maximum": 1000,
								"default": 250,
								"description": "How many people to read at most. Capped at 1000; default 250."
							}
						},
						"required": ["type", "postUrl"],
						"additionalProperties": false
					}
				]
			},
			"LinkedinPerson": {
				"type": "object",
				"properties": {
					"profileUrl": {
						"type": "string",
						"format": "uri",
						"example": "https://www.linkedin.com/in/jane-doe"
					},
					"publicIdentifier": {
						"type": "string",
						"example": "jane-doe"
					},
					"providerId": {
						"type": "string",
						"description": "LinkedIn's member id, when the search returned it.",
						"example": "ACoAAB1x2y3z"
					},
					"firstName": {
						"type": "string"
					},
					"lastName": {
						"type": "string"
					},
					"fullName": {
						"type": "string"
					},
					"headline": {
						"type": "string"
					},
					"title": {
						"type": "string"
					},
					"company": {
						"type": "string"
					},
					"location": {
						"type": "string"
					},
					"avatarUrl": {
						"type": "string",
						"format": "uri"
					}
				},
				"required": ["profileUrl"]
			},
			"SearchPeopleInput": {
				"type": "object",
				"properties": {
					"senderId": {
						"type": "string",
						"description": "The sender whose account searches. A sandbox sender only searches the simulated population; a real one uses LinkedIn's own limits (Classic search returns 10 per page)."
					},
					"url": {
						"type": "string",
						"maxLength": 4000,
						"format": "uri",
						"example": "https://www.linkedin.com/search/results/people/?keywords=head%20of%20revops",
						"description": "A pasted LinkedIn or Sales Navigator people-search URL. Give url or filters."
					},
					"filters": {
						"$ref": "#/components/schemas/PeopleSearchFilters"
					},
					"cursor": {
						"type": "string",
						"maxLength": 4000,
						"description": "meta.nextCursor of the previous page."
					}
				},
				"required": ["senderId"],
				"additionalProperties": false
			},
			"SearchParameter": {
				"type": "object",
				"properties": {
					"id": {
						"type": "string",
						"description": "Pass it in filters.locationIds / industryIds / companyIds.",
						"example": "103644278"
					},
					"title": {
						"type": "string",
						"example": "United States"
					}
				},
				"required": ["id", "title"]
			},
			"BlocklistEntry": {
				"type": "object",
				"properties": {
					"id": {
						"type": "string",
						"example": "blk_Lp4oK8jH2gF6dS0aQ1wE3"
					},
					"kind": {
						"type": "string",
						"enum": ["profile", "company"]
					},
					"value": {
						"type": "string",
						"description": "profile: the LinkedIn identifier (vanity name or member id); company: the company name.",
						"example": "jane-doe"
					},
					"createdAt": {
						"type": "string",
						"format": "date-time"
					}
				},
				"required": ["id", "kind", "value", "createdAt"]
			},
			"AddBlocklistEntriesInput": {
				"type": "object",
				"properties": {
					"entries": {
						"type": "array",
						"items": {
							"$ref": "#/components/schemas/BlocklistEntryInput"
						},
						"minItems": 1,
						"maxItems": 1000,
						"description": "Blocked people and companies are never imported and never enrolled in a campaign."
					}
				},
				"required": ["entries"],
				"additionalProperties": false
			},
			"BlocklistEntryInput": {
				"type": "object",
				"properties": {
					"kind": {
						"type": "string",
						"enum": ["profile", "company"]
					},
					"value": {
						"type": "string",
						"minLength": 1,
						"maxLength": 2000,
						"description": "profile: a LinkedIn profile URL or identifier; company: the company name as LinkedIn shows it."
					}
				},
				"required": ["kind", "value"],
				"additionalProperties": false
			},
			"Campaign": {
				"type": "object",
				"properties": {
					"id": {
						"type": "string",
						"example": "cmp_Lp0oKi9JuHy7GtFr6DeSw"
					},
					"name": {
						"type": "string",
						"example": "RevOps heads · DACH"
					},
					"status": {
						"type": "string",
						"enum": ["draft", "running", "paused", "completed", "archived"]
					},
					"senderIds": {
						"type": "array",
						"items": {
							"type": "string"
						},
						"description": "The sender pool: leads are spread round-robin across it, each sender within its own limits."
					},
					"listIds": {
						"type": "array",
						"items": {
							"type": "string"
						}
					},
					"steps": {
						"type": "array",
						"items": {
							"$ref": "#/components/schemas/CampaignStep"
						}
					},
					"settings": {
						"$ref": "#/components/schemas/CampaignSettings"
					},
					"directLeadCount": {
						"type": "integer",
						"description": "Leads added straight to the campaign (POST /v1/campaigns/{id}/leads), outside any list."
					},
					"stats": {
						"$ref": "#/components/schemas/CampaignFunnel"
					},
					"launchedAt": {
						"type": "string",
						"format": "date-time"
					},
					"completedAt": {
						"type": "string",
						"format": "date-time"
					},
					"archivedAt": {
						"type": "string",
						"format": "date-time"
					},
					"createdAt": {
						"type": "string",
						"format": "date-time"
					},
					"updatedAt": {
						"type": "string",
						"format": "date-time"
					}
				},
				"required": [
					"id",
					"name",
					"status",
					"senderIds",
					"listIds",
					"steps",
					"settings",
					"directLeadCount",
					"stats",
					"createdAt",
					"updatedAt"
				]
			},
			"CampaignStep": {
				"oneOf": [
					{
						"$ref": "#/components/schemas/VisitProfileStep"
					},
					{
						"$ref": "#/components/schemas/LikePostStep"
					},
					{
						"$ref": "#/components/schemas/InviteStep"
					},
					{
						"$ref": "#/components/schemas/MessageStep"
					}
				],
				"discriminator": {
					"propertyName": "type",
					"mapping": {
						"visit_profile": "#/components/schemas/VisitProfileStep",
						"like_post": "#/components/schemas/LikePostStep",
						"invite": "#/components/schemas/InviteStep",
						"message": "#/components/schemas/MessageStep"
					}
				}
			},
			"VisitProfileStep": {
				"type": "object",
				"properties": {
					"type": {
						"type": "string",
						"enum": ["visit_profile"]
					},
					"delay": {
						"$ref": "#/components/schemas/StepDelay"
					}
				},
				"required": ["type"],
				"additionalProperties": false,
				"description": "Visit their profile (they see the view). Counts against the sender's daily profile views."
			},
			"StepDelay": {
				"type": "object",
				"properties": {
					"amount": {
						"type": "integer",
						"minimum": 0,
						"maximum": 1000
					},
					"unit": {
						"type": "string",
						"enum": ["minutes", "hours", "days"]
					}
				},
				"default": {
					"amount": 0,
					"unit": "minutes"
				},
				"required": ["amount", "unit"],
				"additionalProperties": false,
				"description": "How long to wait before this step, counted from the previous step's completion — or, for the step right after an invite, from the moment the invitation was accepted. The first step's delay counts from enrollment. Sandbox senders divide delays by SANDBOX_TIME_SCALE (a day passes in a minute by default)."
			},
			"LikePostStep": {
				"type": "object",
				"properties": {
					"type": {
						"type": "string",
						"enum": ["like_post"]
					},
					"delay": {
						"$ref": "#/components/schemas/StepDelay"
					}
				},
				"required": ["type"],
				"additionalProperties": false,
				"description": "Like their most recent post. Skipped silently when they have no post. Counts against the sender's daily post likes."
			},
			"InviteStep": {
				"type": "object",
				"properties": {
					"type": {
						"type": "string",
						"enum": ["invite"]
					},
					"delay": {
						"$ref": "#/components/schemas/StepDelay"
					},
					"note": {
						"type": "string",
						"maxLength": 1000,
						"description": "Optional invitation note, a template ({{firstName}}, {{fields.x}}…). At most 300 characters once rendered: a lead whose note renders longer is blocked in preview and never sent.",
						"example": "Hi {{firstName | \"there\"}}, {{fields.icebreaker}}"
					}
				},
				"required": ["type"],
				"additionalProperties": false,
				"description": "Send a connection invitation. At most one per campaign. Skipped (marked skipped) when they are already connected; treated as sent when an invitation is already pending. The next step waits for the acceptance; after settings.acceptanceWindowDays without it the invitation is withdrawn and the lead completes with stopReason not_accepted."
			},
			"MessageStep": {
				"type": "object",
				"properties": {
					"type": {
						"type": "string",
						"enum": ["message"]
					},
					"delay": {
						"$ref": "#/components/schemas/StepDelay"
					},
					"text": {
						"type": "string",
						"minLength": 1,
						"maxLength": 10000,
						"description": "The message, a template. At most 8000 characters once rendered. Only ever sent to a 1st-degree connection.",
						"example": "Thanks for connecting, {{firstName}}! {{fields.opener | \"Curious how you run RevOps today?\"}}"
					}
				},
				"required": ["type", "text"],
				"additionalProperties": false,
				"description": "Send a LinkedIn message. Needs an invite step before it, or settings.audience = connected_only."
			},
			"CampaignSettings": {
				"type": "object",
				"properties": {
					"acceptanceWindowDays": {
						"type": "integer",
						"minimum": 1,
						"maximum": 30,
						"default": 14,
						"description": "Days to wait for an invitation to be accepted before withdrawing it (1–30, default 14). With secondChance, counted from the first invitation: every invitation of the lead is withdrawn when it ends."
					},
					"audience": {
						"type": "string",
						"enum": ["anyone", "connected_only"],
						"default": "anyone",
						"description": "anyone (default): people who aren't connected get the invite step. connected_only: only people already connected to their assigned sender — no invite step allowed, others are stopped with not_connected after the first profile lookup."
					},
					"secondChance": {
						"$ref": "#/components/schemas/SecondChance"
					},
					"ifAlreadyConnected": {
						"type": "string",
						"enum": ["continue", "skip_lead"],
						"default": "continue",
						"description": "Campaigns with an invite step, for someone found to be a 1st-degree connection already (of their sender, or of a second-chance sender who looks them up). continue (default): no invitation, the sequence goes on from the step after the invite — from the sender they are connected to, which becomes the enrollment's sender — and the enrollment is flagged alreadyConnected (no lead.invite_accepted: write the next message so it reads well to an existing connection). skip_lead: the lead completes at once with stopReason already_connected, nothing sent; pending invitations are withdrawn."
					},
					"senderAssignment": {
						"type": "string",
						"enum": ["round_robin", "one_per_company"],
						"default": "round_robin",
						"description": "round_robin (default): leads are spread across the pool in turn. one_per_company: every lead of the same company (as their profile names it when they enroll, case and spacing ignored) starts from the sender the first one got; leads without a company go round-robin."
					}
				},
				"additionalProperties": false
			},
			"SecondChance": {
				"type": "object",
				"properties": {
					"extraSenders": {
						"type": "integer",
						"minimum": 0,
						"maximum": 10,
						"description": "How many other senders of the pool may invite a lead who hasn't accepted yet (0 turns it off, at most 10). Each one in turn: the next pool sender that hasn't invited them visits their profile and invites them.",
						"example": 1
					},
					"after": {
						"allOf": [
							{
								"$ref": "#/components/schemas/StepDelay"
							},
							{
								"description": "How long after the previous invitation the next sender steps in. Must be shorter than the acceptance window: no invitation goes out once the window has closed.",
								"example": {
									"amount": 3,
									"unit": "days"
								}
							}
						]
					}
				},
				"required": ["extraSenders", "after"],
				"additionalProperties": false,
				"description": "Multi-sender invitations. If the lead hasn't accepted the first sender's invitation `after` this long, another sender of the campaign's pool visits their profile and invites them too — up to `extraSenders` more senders, each within its own limits, working hours and warm-up, and only while the acceptance window (counted from the first invitation) is still open. Whichever invitation they accept makes that sender the enrollment's sender from then on (the next steps and the conversation are its); every other pending invitation is withdrawn at once, and all of them when the window closes. A second-chance sender who is already connected to the lead never invites: ifAlreadyConnected decides what happens."
			},
			"CampaignFunnel": {
				"type": "object",
				"properties": {
					"enrolled": {
						"type": "integer",
						"description": "Leads enrolled (counted against the plan). Leads skipped at enrollment are not included."
					},
					"active": {
						"type": "integer",
						"description": "Live enrollments: active, waiting or awaiting acceptance."
					},
					"invited": {
						"type": "integer"
					},
					"accepted": {
						"type": "integer"
					},
					"acceptanceRate": {
						"type": "number",
						"minimum": 0,
						"maximum": 1,
						"description": "accepted / invited, 0–1."
					},
					"messaged": {
						"type": "integer",
						"description": "Enrollments that got at least one campaign message."
					},
					"replied": {
						"type": "integer"
					},
					"replyRate": {
						"type": "number",
						"minimum": 0,
						"maximum": 1,
						"description": "replied / contacted (invited or messaged), 0–1. Replies after the sequence finished count too."
					},
					"completed": {
						"type": "integer"
					},
					"failed": {
						"type": "integer"
					},
					"stopped": {
						"type": "integer",
						"description": "Stopped by someone or by archiving, plus leads skipped at enrollment (blocklisted, already in a campaign, template problems)."
					}
				},
				"required": [
					"enrolled",
					"active",
					"invited",
					"accepted",
					"acceptanceRate",
					"messaged",
					"replied",
					"replyRate",
					"completed",
					"failed",
					"stopped"
				]
			},
			"CreateCampaignInput": {
				"type": "object",
				"properties": {
					"name": {
						"type": "string",
						"minLength": 1,
						"maxLength": 120,
						"example": "RevOps · DACH"
					},
					"senderIds": {
						"type": "array",
						"items": {
							"type": "string"
						},
						"maxItems": 50,
						"default": [],
						"description": "The sender pool. Leads are assigned round-robin; each sender acts within its own limits and working hours. Every sender must be active to launch."
					},
					"listIds": {
						"type": "array",
						"items": {
							"type": "string"
						},
						"maxItems": 50,
						"default": [],
						"description": "The audience. Leads added to these lists later join a running campaign automatically (within a few minutes)."
					},
					"steps": {
						"type": "array",
						"items": {
							"$ref": "#/components/schemas/CampaignStep"
						},
						"maxItems": 20,
						"default": [],
						"description": "The sequence, run in order for every lead: visit_profile, like_post, invite (at most one, optional note ≤ 300 rendered characters), message (≤ 8000 rendered characters, only to 1st-degree connections: needs an invite step before it unless settings.audience is connected_only). Each step has a delay from the previous step's completion; the step right after an invite counts its delay from the acceptance. Before the first step the sender looks the person up (no visible visit) to learn whether they are connected. Templates use {{firstName}}, {{lastName}}, {{fullName}}, {{company}}, {{title}}, {{headline}}, {{location}}, {{sender.firstName}}, {{sender.fullName}}, {{fields.<key>}} and fallbacks like {{firstName | \"there\"}}; a variable with no value and no fallback blocks that lead (it is never sent). An empty sequence is allowed in a draft but cannot be launched."
					},
					"settings": {
						"$ref": "#/components/schemas/CampaignSettings"
					}
				},
				"required": ["name"],
				"additionalProperties": false
			},
			"UpdateCampaignInput": {
				"type": "object",
				"properties": {
					"name": {
						"type": "string",
						"minLength": 1,
						"maxLength": 120,
						"description": "Can change at any time."
					},
					"senderIds": {
						"type": "array",
						"items": {
							"type": "string"
						},
						"maxItems": 50,
						"description": "Only while draft or paused. Enrollments keep the sender they were assigned; new ones use the new pool."
					},
					"listIds": {
						"type": "array",
						"items": {
							"type": "string"
						},
						"maxItems": 50,
						"description": "Only while draft or paused."
					},
					"steps": {
						"type": "array",
						"items": {
							"$ref": "#/components/schemas/CampaignStep"
						},
						"maxItems": 20,
						"description": "Only while draft or paused. Live enrollments continue from the same step number in the new sequence; their next planned step is re-planned."
					},
					"settings": {
						"$ref": "#/components/schemas/CampaignSettingsPatch"
					}
				},
				"additionalProperties": false
			},
			"CampaignSettingsPatch": {
				"type": "object",
				"properties": {
					"acceptanceWindowDays": {
						"type": "integer",
						"minimum": 1,
						"maximum": 30,
						"description": "Days to wait for an invitation to be accepted before withdrawing it (1–30, default 14). With secondChance, counted from the first invitation: every invitation of the lead is withdrawn when it ends."
					},
					"audience": {
						"type": "string",
						"enum": ["anyone", "connected_only"],
						"description": "anyone (default): people who aren't connected get the invite step. connected_only: only people already connected to their assigned sender — no invite step allowed, others are stopped with not_connected after the first profile lookup."
					},
					"secondChance": {
						"$ref": "#/components/schemas/SecondChance"
					},
					"ifAlreadyConnected": {
						"type": "string",
						"enum": ["continue", "skip_lead"],
						"description": "Campaigns with an invite step, for someone found to be a 1st-degree connection already (of their sender, or of a second-chance sender who looks them up). continue (default): no invitation, the sequence goes on from the step after the invite — from the sender they are connected to, which becomes the enrollment's sender — and the enrollment is flagged alreadyConnected (no lead.invite_accepted: write the next message so it reads well to an existing connection). skip_lead: the lead completes at once with stopReason already_connected, nothing sent; pending invitations are withdrawn."
					},
					"senderAssignment": {
						"type": "string",
						"enum": ["round_robin", "one_per_company"],
						"description": "round_robin (default): leads are spread across the pool in turn. one_per_company: every lead of the same company (as their profile names it when they enroll, case and spacing ignored) starts from the sender the first one got; leads without a company go round-robin."
					}
				},
				"additionalProperties": false,
				"description": "Only while draft or paused."
			},
			"CampaignPreview": {
				"type": "object",
				"properties": {
					"campaignId": {
						"type": "string"
					},
					"canLaunch": {
						"type": "boolean",
						"description": "No blocking campaign-level issue (only meaningful for a draft)."
					},
					"campaignIssues": {
						"type": "array",
						"items": {
							"$ref": "#/components/schemas/CampaignIssue"
						}
					},
					"totals": {
						"type": "object",
						"properties": {
							"leads": {
								"type": "integer",
								"description": "Every lead of the lists plus the leads added directly."
							},
							"eligible": {
								"type": "integer"
							},
							"blocked": {
								"type": "integer"
							},
							"enrollableThisMonth": {
								"type": "integer",
								"description": "How many of the eligible leads the plan's monthly enrollment cap lets in now; the rest join automatically when it resets."
							},
							"issues": {
								"type": "object",
								"properties": {
									"missing_variable": {
										"type": "integer"
									},
									"note_too_long": {
										"type": "integer"
									},
									"message_too_long": {
										"type": "integer"
									},
									"blocklisted": {
										"type": "integer"
									},
									"already_in_campaign": {
										"type": "integer"
									},
									"already_enrolled": {
										"type": "integer"
									}
								},
								"description": "How many leads have each issue (a lead may have several)."
							}
						},
						"required": [
							"leads",
							"eligible",
							"blocked",
							"enrollableThisMonth",
							"issues"
						]
					},
					"leads": {
						"type": "array",
						"items": {
							"$ref": "#/components/schemas/PreviewLead"
						}
					}
				},
				"required": [
					"campaignId",
					"canLaunch",
					"campaignIssues",
					"totals",
					"leads"
				]
			},
			"CampaignIssue": {
				"type": "object",
				"properties": {
					"code": {
						"type": "string",
						"enum": [
							"no_senders",
							"sender_not_active",
							"no_steps",
							"no_leads",
							"plan_limit",
							"live_campaign_limit",
							"second_chance_pool_too_small"
						]
					},
					"blocking": {
						"type": "boolean",
						"description": "true: launch is refused until it is fixed."
					},
					"message": {
						"type": "string"
					},
					"senderIds": {
						"type": "array",
						"items": {
							"type": "string"
						}
					}
				},
				"required": ["code", "blocking", "message"]
			},
			"PreviewLead": {
				"type": "object",
				"properties": {
					"lead": {
						"$ref": "#/components/schemas/LeadSummary"
					},
					"eligible": {
						"type": "boolean",
						"description": "false when any issue blocks this lead: it would be skipped."
					},
					"sender": {
						"$ref": "#/components/schemas/SenderSummary"
					},
					"steps": {
						"type": "array",
						"items": {
							"$ref": "#/components/schemas/PreviewStep"
						}
					},
					"issues": {
						"type": "array",
						"items": {
							"$ref": "#/components/schemas/LeadIssue"
						}
					}
				},
				"required": ["lead", "eligible", "steps", "issues"]
			},
			"LeadSummary": {
				"type": "object",
				"properties": {
					"id": {
						"type": "string",
						"example": "lead_Qw3rTy7uIo9pAs1dFg2hJ"
					},
					"profileUrl": {
						"type": "string",
						"format": "uri"
					},
					"fullName": {
						"type": "string"
					},
					"firstName": {
						"type": "string"
					},
					"lastName": {
						"type": "string"
					},
					"headline": {
						"type": "string"
					},
					"company": {
						"type": "string"
					},
					"avatarUrl": {
						"type": "string",
						"format": "uri"
					}
				},
				"required": ["id", "profileUrl"]
			},
			"SenderSummary": {
				"type": "object",
				"properties": {
					"id": {
						"type": "string",
						"example": "snd_8hJ2kLm0PqRsT4uVwXyZa"
					},
					"name": {
						"type": "string"
					},
					"kind": {
						"type": "string",
						"enum": ["linkedin", "sandbox"]
					},
					"status": {
						"type": "string",
						"enum": [
							"connecting",
							"active",
							"paused",
							"needs_reconnect",
							"restricted",
							"disconnected"
						]
					}
				},
				"required": ["id", "name", "kind", "status"]
			},
			"PreviewStep": {
				"type": "object",
				"properties": {
					"index": {
						"type": "integer"
					},
					"type": {
						"type": "string",
						"enum": ["visit_profile", "like_post", "invite", "message"]
					},
					"text": {
						"type": "string",
						"description": "The rendered note or message, exactly as it would be sent."
					},
					"length": {
						"type": "integer"
					}
				},
				"required": ["index", "type"]
			},
			"LeadIssue": {
				"type": "object",
				"properties": {
					"code": {
						"type": "string",
						"enum": [
							"missing_variable",
							"note_too_long",
							"message_too_long",
							"blocklisted",
							"already_in_campaign",
							"already_enrolled"
						]
					},
					"message": {
						"type": "string"
					},
					"stepIndex": {
						"type": "integer"
					},
					"variables": {
						"type": "array",
						"items": {
							"type": "string"
						},
						"description": "For missing_variable: the variables without a value."
					}
				},
				"required": ["code", "message"]
			},
			"AddCampaignLeadResult": {
				"type": "object",
				"properties": {
					"input": {
						"type": "string",
						"description": "The leadId or profileUrl as given."
					},
					"leadId": {
						"type": "string"
					},
					"outcome": {
						"type": "string",
						"enum": ["enrolled", "queued", "skipped", "invalid"],
						"description": "enrolled: live in the running or paused campaign. queued: the campaign is a draft; it enrolls at launch. skipped: see issues (re-adding it after fixing them re-checks it). invalid: not a lead of this workspace or not a LinkedIn profile URL."
					},
					"enrollmentId": {
						"type": "string"
					},
					"issues": {
						"type": "array",
						"items": {
							"$ref": "#/components/schemas/LeadIssue"
						}
					},
					"message": {
						"type": "string"
					}
				},
				"required": ["input", "outcome", "issues"]
			},
			"AddCampaignLeadsInput": {
				"type": "object",
				"properties": {
					"leads": {
						"type": "array",
						"items": {
							"type": "object",
							"properties": {
								"leadId": {
									"type": "string",
									"description": "A lead of this workspace."
								},
								"profileUrl": {
									"type": "string",
									"maxLength": 500,
									"description": "A LinkedIn profile URL (or bare identifier); the lead is created when the workspace doesn't know it yet.",
									"example": "https://www.linkedin.com/in/jane-doe"
								},
								"fields": {
									"$ref": "#/components/schemas/LeadFields"
								}
							},
							"additionalProperties": false
						},
						"minItems": 1,
						"maxItems": 100
					}
				},
				"required": ["leads"],
				"additionalProperties": false
			},
			"CampaignStats": {
				"type": "object",
				"properties": {
					"campaignId": {
						"type": "string"
					},
					"totals": {
						"$ref": "#/components/schemas/CampaignFunnel"
					},
					"contacted": {
						"type": "integer",
						"description": "Invited or messaged: the base of replyRate."
					},
					"steps": {
						"type": "array",
						"items": {
							"$ref": "#/components/schemas/CampaignStepStats"
						}
					},
					"senders": {
						"type": "array",
						"items": {
							"$ref": "#/components/schemas/CampaignSenderStats"
						}
					}
				},
				"required": ["campaignId", "totals", "contacted", "steps", "senders"]
			},
			"CampaignStepStats": {
				"type": "object",
				"properties": {
					"index": {
						"type": "integer"
					},
					"type": {
						"type": "string",
						"enum": ["visit_profile", "like_post", "invite", "message"]
					},
					"done": {
						"type": "integer"
					},
					"skipped": {
						"type": "integer"
					},
					"failed": {
						"type": "integer"
					},
					"pending": {
						"type": "integer",
						"description": "Planned or running right now."
					}
				},
				"required": ["index", "type", "done", "skipped", "failed", "pending"]
			},
			"CampaignSenderStats": {
				"allOf": [
					{
						"$ref": "#/components/schemas/CampaignFunnel"
					},
					{
						"type": "object",
						"properties": {
							"sender": {
								"$ref": "#/components/schemas/SenderSummary"
							}
						},
						"required": ["sender"]
					}
				]
			},
			"Enrollment": {
				"type": "object",
				"properties": {
					"id": {
						"type": "string",
						"example": "enr_As2dF3gH4jK5lQ6wE7rT8"
					},
					"campaignId": {
						"type": "string"
					},
					"status": {
						"type": "string",
						"enum": [
							"active",
							"waiting",
							"awaiting_acceptance",
							"completed",
							"replied",
							"stopped",
							"failed"
						]
					},
					"stepIndex": {
						"type": "integer",
						"description": "The step the enrollment is at (0-based); equals the number of steps once finished."
					},
					"nextActionAt": {
						"type": "string",
						"format": "date-time",
						"description": "When its next action is planned. For awaiting_acceptance, when the invitation will be withdrawn."
					},
					"waitingReason": {
						"type": "string",
						"description": "Live enrollments only: what happens next and why, in plain English, as of the moment you read it — it never names a time already past. E.g. \"Next: send invite — sender's daily invite cap reached (20/20), next slot Tue 09:12 Europe/Madrid\", \"Waiting: sender Ada paused by you\", \"Waiting: Ada needs to reconnect LinkedIn\", \"Waiting: LinkedIn limit reached, Ada acts again Tue 09:00 Europe/Madrid\"."
					},
					"stopReason": {
						"type": "string",
						"enum": [
							"blocklisted",
							"already_in_campaign",
							"missing_variable",
							"note_too_long",
							"message_too_long",
							"not_connected",
							"not_accepted",
							"not_found",
							"cannot_invite",
							"linkedin_error",
							"stopped_by_user",
							"campaign_archived",
							"already_connected"
						]
					},
					"conversationId": {
						"type": "string",
						"description": "The conversation between its sender and the lead, once there is one (GET /v1/conversations/{id}).",
						"example": "cnv_OYRxBhxi"
					},
					"stopDetail": {
						"type": "string",
						"description": "Finished enrollments: how it ended, in words (a failure's cause, why a lead was skipped at enrollment)."
					},
					"fields": {
						"$ref": "#/components/schemas/LeadFields"
					},
					"sender": {
						"$ref": "#/components/schemas/SenderSummary"
					},
					"lead": {
						"$ref": "#/components/schemas/LeadSummary"
					},
					"enrolledAt": {
						"type": "string",
						"format": "date-time",
						"description": "When it started (and began counting against the plan); absent for leads skipped at enrollment."
					},
					"invitedAt": {
						"type": "string",
						"format": "date-time",
						"description": "When the first invitation went out (or was found pending). Second-chance invitations are listed in the enrollment's detail (`invitations`)."
					},
					"connectedAt": {
						"type": "string",
						"format": "date-time"
					},
					"alreadyConnected": {
						"type": "boolean",
						"description": "true when the person was found to be a 1st-degree connection of the enrollment's sender already, so no invitation was needed (settings.ifAlreadyConnected = continue): nothing announced them as newly connected."
					},
					"repliedAt": {
						"type": "string",
						"format": "date-time"
					},
					"finishedAt": {
						"type": "string",
						"format": "date-time"
					},
					"createdAt": {
						"type": "string",
						"format": "date-time"
					},
					"updatedAt": {
						"type": "string",
						"format": "date-time"
					}
				},
				"required": [
					"id",
					"campaignId",
					"status",
					"stepIndex",
					"fields",
					"lead",
					"alreadyConnected",
					"createdAt",
					"updatedAt"
				]
			},
			"EnrollmentDetail": {
				"allOf": [
					{
						"$ref": "#/components/schemas/Enrollment"
					},
					{
						"type": "object",
						"properties": {
							"actions": {
								"type": "array",
								"items": {
									"$ref": "#/components/schemas/Action"
								},
								"description": "Every action planned or done for this enrollment, oldest first. Each is done by its own sender: a second chance's visit, invite and withdrawal belong to the extra sender."
							},
							"invitations": {
								"type": "array",
								"items": {
									"$ref": "#/components/schemas/EnrollmentInvitation"
								},
								"description": "Every invitation the enrollment sent, one per sender, oldest first: the first sender's, then each second chance's."
							}
						},
						"required": ["actions", "invitations"]
					}
				]
			},
			"Action": {
				"type": "object",
				"properties": {
					"id": {
						"type": "string",
						"example": "act_Mn8bVc7xZa6sDf5gHj4kL"
					},
					"type": {
						"type": "string",
						"enum": [
							"fetch_profile",
							"visit_profile",
							"like_post",
							"invite",
							"message",
							"withdraw"
						]
					},
					"status": {
						"type": "string",
						"enum": [
							"pending",
							"running",
							"done",
							"failed",
							"skipped",
							"cancelled"
						]
					},
					"stepIndex": {
						"type": "integer",
						"description": "The step it performs (0-based); absent for the implicit fetch_profile."
					},
					"dueAt": {
						"type": "string",
						"format": "date-time"
					},
					"startedAt": {
						"type": "string",
						"format": "date-time"
					},
					"finishedAt": {
						"type": "string",
						"format": "date-time"
					},
					"attempt": {
						"type": "integer"
					},
					"errorCode": {
						"type": "string"
					},
					"errorDetail": {
						"type": "string",
						"description": "Why it failed or was skipped, in plain English."
					},
					"renderedText": {
						"type": "string",
						"description": "The note or message exactly as sent."
					}
				},
				"required": ["id", "type", "status", "dueAt", "attempt"]
			},
			"EnrollmentInvitation": {
				"type": "object",
				"properties": {
					"senderId": {
						"type": "string"
					},
					"status": {
						"type": "string",
						"enum": ["pending", "accepted", "withdrawn", "failed"]
					},
					"secondChance": {
						"type": "boolean",
						"description": "true for an extra sender's invitation (settings.secondChance)."
					},
					"invitedAt": {
						"type": "string",
						"format": "date-time",
						"description": "Absent for an attempt LinkedIn refused (status failed)."
					},
					"acceptedAt": {
						"type": "string",
						"format": "date-time"
					},
					"withdrawnAt": {
						"type": "string",
						"format": "date-time"
					},
					"detail": {
						"type": "string",
						"description": "Why it failed or was withdrawn, in plain English."
					}
				},
				"required": ["senderId", "status", "secondChance"]
			},
			"UpdateEnrollmentInput": {
				"type": "object",
				"properties": {
					"fields": {
						"$ref": "#/components/schemas/LeadFields"
					}
				},
				"required": ["fields"],
				"additionalProperties": false
			},
			"Conversation": {
				"type": "object",
				"properties": {
					"id": {
						"type": "string",
						"example": "cnv_Zx1cV2bN3mQ4wE5rT6yU7"
					},
					"sender": {
						"$ref": "#/components/schemas/SenderSummary"
					},
					"lead": {
						"$ref": "#/components/schemas/LeadSummary"
					},
					"campaign": {
						"type": "object",
						"properties": {
							"id": {
								"type": "string"
							},
							"name": {
								"type": "string"
							}
						},
						"required": ["id", "name"],
						"description": "The campaign the lead is (or last was) in with this sender."
					},
					"lastMessage": {
						"type": "object",
						"properties": {
							"text": {
								"type": "string"
							},
							"direction": {
								"type": "string",
								"enum": ["outbound", "inbound"]
							},
							"sentAt": {
								"type": "string",
								"format": "date-time"
							}
						},
						"required": ["text", "direction", "sentAt"]
					},
					"lastMessageAt": {
						"type": "string",
						"format": "date-time"
					},
					"unread": {
						"type": "boolean",
						"description": "An inbound message arrived since the conversation was last opened."
					},
					"createdAt": {
						"type": "string",
						"format": "date-time"
					}
				},
				"required": ["id", "sender", "lead", "unread", "createdAt"]
			},
			"ConversationDetail": {
				"allOf": [
					{
						"$ref": "#/components/schemas/Conversation"
					},
					{
						"type": "object",
						"properties": {
							"messages": {
								"type": "array",
								"items": {
									"$ref": "#/components/schemas/Message"
								},
								"description": "Every message, oldest first."
							}
						},
						"required": ["messages"]
					}
				]
			},
			"Message": {
				"type": "object",
				"properties": {
					"id": {
						"type": "string",
						"example": "msg_Pl9oKm8iJn7uHb6yGv5tF"
					},
					"conversationId": {
						"type": "string"
					},
					"direction": {
						"type": "string",
						"enum": ["outbound", "inbound"]
					},
					"text": {
						"type": "string"
					},
					"sentAt": {
						"type": "string",
						"format": "date-time"
					},
					"actionId": {
						"type": "string",
						"description": "The campaign action that sent it, for campaign messages."
					}
				},
				"required": ["id", "conversationId", "direction", "text", "sentAt"]
			},
			"SendConversationMessageInput": {
				"type": "object",
				"properties": {
					"text": {
						"type": "string",
						"minLength": 1,
						"maxLength": 8000,
						"description": "Plain text (no templates), sent by the conversation's sender. Counts against that sender's daily message cap and is refused when the cap is reached or the sender is not active."
					}
				},
				"required": ["text"],
				"additionalProperties": false
			},
			"SenderConnectedEventData": {
				"type": "object",
				"properties": {
					"senderId": {
						"type": "string",
						"description": "The sender's id.",
						"example": "snd_0yUkG9TD"
					},
					"name": {
						"type": "string"
					},
					"kind": {
						"type": "string",
						"enum": ["linkedin", "sandbox"]
					},
					"status": {
						"type": "string",
						"enum": [
							"connecting",
							"active",
							"paused",
							"needs_reconnect",
							"restricted",
							"disconnected"
						],
						"description": "The sender's status after the event. A sender resting after a LinkedIn limit stays active, with `until`."
					},
					"profileUrl": {
						"type": "string"
					},
					"statusDetail": {
						"type": "string",
						"description": "The status in words, as GET /v1/senders/{id} shows it."
					},
					"reason": {
						"type": "string",
						"enum": [
							"paused_by_user",
							"resumed_by_user",
							"plan_limit",
							"linkedin_limit",
							"hold_expired",
							"session_expired",
							"account_restricted",
							"account_status",
							"connected",
							"sandbox_created"
						]
					},
					"until": {
						"type": "string",
						"format": "date-time",
						"description": "When a rest ends (reason linkedin_limit): the sender acts again by itself from then."
					},
					"reconnected": {
						"type": "boolean",
						"description": "true when an existing sender came back (reconnected through a connect link or recovered by LinkedIn)."
					}
				},
				"required": ["senderId", "name", "kind", "status", "reconnected"],
				"additionalProperties": false
			},
			"SenderNeedsReconnectEventData": {
				"type": "object",
				"properties": {
					"senderId": {
						"type": "string",
						"description": "The sender's id.",
						"example": "snd_0yUkG9TD"
					},
					"name": {
						"type": "string"
					},
					"kind": {
						"type": "string",
						"enum": ["linkedin", "sandbox"]
					},
					"status": {
						"type": "string",
						"enum": [
							"connecting",
							"active",
							"paused",
							"needs_reconnect",
							"restricted",
							"disconnected"
						],
						"description": "The sender's status after the event. A sender resting after a LinkedIn limit stays active, with `until`."
					},
					"profileUrl": {
						"type": "string"
					},
					"statusDetail": {
						"type": "string",
						"description": "The status in words, as GET /v1/senders/{id} shows it."
					},
					"reason": {
						"type": "string",
						"enum": [
							"paused_by_user",
							"resumed_by_user",
							"plan_limit",
							"linkedin_limit",
							"hold_expired",
							"session_expired",
							"account_restricted",
							"account_status",
							"connected",
							"sandbox_created"
						]
					},
					"until": {
						"type": "string",
						"format": "date-time",
						"description": "When a rest ends (reason linkedin_limit): the sender acts again by itself from then."
					},
					"reconnectUrl": {
						"type": "string",
						"format": "uri",
						"description": "A short connect link (valid 7 days) that repairs this sender: give it to the account owner, who opens it, signs in to LinkedIn again and comes back. Present for real LinkedIn senders; the workspace owners are emailed the same link (at most once a day per sender).",
						"example": "https://getoutvoy.com/c/7KQ2M9XH4P"
					}
				},
				"required": ["senderId", "name", "kind", "status"],
				"additionalProperties": false
			},
			"SenderEventData": {
				"type": "object",
				"properties": {
					"senderId": {
						"type": "string",
						"description": "The sender's id.",
						"example": "snd_0yUkG9TD"
					},
					"name": {
						"type": "string"
					},
					"kind": {
						"type": "string",
						"enum": ["linkedin", "sandbox"]
					},
					"status": {
						"type": "string",
						"enum": [
							"connecting",
							"active",
							"paused",
							"needs_reconnect",
							"restricted",
							"disconnected"
						],
						"description": "The sender's status after the event. A sender resting after a LinkedIn limit stays active, with `until`."
					},
					"profileUrl": {
						"type": "string"
					},
					"statusDetail": {
						"type": "string",
						"description": "The status in words, as GET /v1/senders/{id} shows it."
					},
					"reason": {
						"type": "string",
						"enum": [
							"paused_by_user",
							"resumed_by_user",
							"plan_limit",
							"linkedin_limit",
							"hold_expired",
							"session_expired",
							"account_restricted",
							"account_status",
							"connected",
							"sandbox_created"
						]
					},
					"until": {
						"type": "string",
						"format": "date-time",
						"description": "When a rest ends (reason linkedin_limit): the sender acts again by itself from then."
					}
				},
				"required": ["senderId", "name", "kind", "status"],
				"additionalProperties": false
			},
			"ImportEventData": {
				"type": "object",
				"properties": {
					"importId": {
						"type": "string",
						"description": "The import's id.",
						"example": "imp_8Y2kARk6"
					},
					"listId": {
						"type": "string",
						"description": "The list it imported into.",
						"example": "list_xWOp0Icf"
					},
					"listName": {
						"type": "string",
						"description": "Absent when the list was deleted meanwhile."
					},
					"senderId": {
						"type": "string"
					},
					"source": {
						"type": "string",
						"enum": ["search", "post_engagers"]
					},
					"found": {
						"type": "integer"
					},
					"imported": {
						"type": "integer"
					},
					"skipped": {
						"type": "integer"
					},
					"error": {
						"type": "string",
						"description": "import.failed only: why it stopped."
					}
				},
				"required": [
					"importId",
					"listId",
					"senderId",
					"source",
					"found",
					"imported",
					"skipped"
				],
				"additionalProperties": false
			},
			"CampaignLaunchedEventData": {
				"type": "object",
				"properties": {
					"campaignId": {
						"type": "string",
						"description": "The campaign's id.",
						"example": "cmp_pToocdWF"
					},
					"campaign": {
						"$ref": "#/components/schemas/EventCampaign"
					},
					"enrolled": {
						"type": "integer"
					},
					"skipped": {
						"type": "integer"
					},
					"waitingForPlan": {
						"type": "integer",
						"description": "Eligible leads over the plan's monthly enrollment cap: they enroll when it resets."
					}
				},
				"required": [
					"campaignId",
					"campaign",
					"enrolled",
					"skipped",
					"waitingForPlan"
				],
				"additionalProperties": false
			},
			"EventCampaign": {
				"type": "object",
				"properties": {
					"id": {
						"type": "string",
						"description": "The campaign's id.",
						"example": "cmp_pToocdWF"
					},
					"name": {
						"type": "string"
					}
				},
				"required": ["id", "name"],
				"additionalProperties": false,
				"description": "The latest campaign this sender ran with the lead, when there is one."
			},
			"CampaignEventData": {
				"type": "object",
				"properties": {
					"campaignId": {
						"type": "string",
						"description": "The campaign's id.",
						"example": "cmp_pToocdWF"
					},
					"campaign": {
						"$ref": "#/components/schemas/EventCampaign"
					}
				},
				"required": ["campaignId", "campaign"],
				"additionalProperties": false
			},
			"LeadEventData": {
				"type": "object",
				"properties": {
					"enrollmentId": {
						"type": "string",
						"description": "The enrollment's id.",
						"example": "enr_xA7Y99RY"
					},
					"campaignId": {
						"type": "string"
					},
					"leadId": {
						"type": "string"
					},
					"senderId": {
						"type": "string"
					},
					"campaign": {
						"$ref": "#/components/schemas/EventCampaign"
					},
					"lead": {
						"$ref": "#/components/schemas/EventLead"
					},
					"sender": {
						"$ref": "#/components/schemas/EventSender"
					}
				},
				"required": [
					"enrollmentId",
					"campaignId",
					"leadId",
					"senderId",
					"campaign",
					"lead",
					"sender"
				],
				"additionalProperties": false
			},
			"EventLead": {
				"type": "object",
				"properties": {
					"id": {
						"type": "string",
						"description": "The lead's id.",
						"example": "lead_kLkaq0WP"
					},
					"name": {
						"type": "string",
						"description": "Absent while LinkedIn hasn't told us the person's name."
					},
					"profileUrl": {
						"type": "string"
					},
					"headline": {
						"type": "string"
					},
					"company": {
						"type": "string"
					},
					"publicIdentifier": {
						"type": "string",
						"description": "Their LinkedIn vanity id (linkedin.com/in/<publicIdentifier>), when known.",
						"example": "ada-lovelace"
					},
					"providerId": {
						"type": "string",
						"description": "Their LinkedIn member id, when known (learned on the first profile lookup): it stays the same when they change their vanity URL.",
						"example": "ACoAAB1x2y3z"
					},
					"redacted": {
						"type": "boolean",
						"enum": [true],
						"description": "Present when the lead was deleted (DELETE /v1/leads/{id}): every personal field of the event was blanked — `profileUrl` is empty, the name, headline and company are gone, and texts and notes are empty — while the ids stay."
					}
				},
				"required": ["id", "profileUrl"],
				"additionalProperties": false
			},
			"EventSender": {
				"type": "object",
				"properties": {
					"id": {
						"type": "string",
						"description": "The sender's id.",
						"example": "snd_0yUkG9TD"
					},
					"name": {
						"type": "string"
					}
				},
				"required": ["id", "name"],
				"additionalProperties": false
			},
			"LeadProfileVisitedEventData": {
				"type": "object",
				"properties": {
					"enrollmentId": {
						"type": "string",
						"description": "The enrollment's id.",
						"example": "enr_xA7Y99RY"
					},
					"campaignId": {
						"type": "string"
					},
					"leadId": {
						"type": "string"
					},
					"senderId": {
						"type": "string"
					},
					"campaign": {
						"$ref": "#/components/schemas/EventCampaign"
					},
					"lead": {
						"$ref": "#/components/schemas/EventLead"
					},
					"sender": {
						"$ref": "#/components/schemas/EventSender"
					},
					"stepIndex": {
						"type": "integer",
						"description": "The step of the sequence (0-based)."
					}
				},
				"required": [
					"enrollmentId",
					"campaignId",
					"leadId",
					"senderId",
					"campaign",
					"lead",
					"sender",
					"stepIndex"
				],
				"additionalProperties": false
			},
			"LeadPostLikedEventData": {
				"type": "object",
				"properties": {
					"enrollmentId": {
						"type": "string",
						"description": "The enrollment's id.",
						"example": "enr_xA7Y99RY"
					},
					"campaignId": {
						"type": "string"
					},
					"leadId": {
						"type": "string"
					},
					"senderId": {
						"type": "string"
					},
					"campaign": {
						"$ref": "#/components/schemas/EventCampaign"
					},
					"lead": {
						"$ref": "#/components/schemas/EventLead"
					},
					"sender": {
						"$ref": "#/components/schemas/EventSender"
					},
					"stepIndex": {
						"type": "integer",
						"description": "The step of the sequence (0-based)."
					},
					"postId": {
						"type": "string"
					}
				},
				"required": [
					"enrollmentId",
					"campaignId",
					"leadId",
					"senderId",
					"campaign",
					"lead",
					"sender",
					"stepIndex",
					"postId"
				],
				"additionalProperties": false
			},
			"LeadInviteSentEventData": {
				"type": "object",
				"properties": {
					"enrollmentId": {
						"type": "string",
						"description": "The enrollment's id.",
						"example": "enr_xA7Y99RY"
					},
					"campaignId": {
						"type": "string"
					},
					"leadId": {
						"type": "string"
					},
					"senderId": {
						"type": "string"
					},
					"campaign": {
						"$ref": "#/components/schemas/EventCampaign"
					},
					"lead": {
						"$ref": "#/components/schemas/EventLead"
					},
					"sender": {
						"$ref": "#/components/schemas/EventSender"
					},
					"stepIndex": {
						"type": "integer",
						"description": "The step of the sequence (0-based)."
					},
					"note": {
						"type": "string",
						"description": "The note exactly as sent; absent for a bare invitation."
					},
					"secondChance": {
						"type": "boolean",
						"description": "true for an invitation from an extra sender (settings.secondChance) while the first one was still unanswered: `senderId` is the inviting sender, not yet the enrollment's."
					}
				},
				"required": [
					"enrollmentId",
					"campaignId",
					"leadId",
					"senderId",
					"campaign",
					"lead",
					"sender",
					"stepIndex"
				],
				"additionalProperties": false
			},
			"LeadInviteAcceptedEventData": {
				"type": "object",
				"properties": {
					"enrollmentId": {
						"type": "string",
						"description": "The enrollment's id.",
						"example": "enr_xA7Y99RY"
					},
					"campaignId": {
						"type": "string"
					},
					"leadId": {
						"type": "string"
					},
					"senderId": {
						"type": "string"
					},
					"campaign": {
						"$ref": "#/components/schemas/EventCampaign"
					},
					"lead": {
						"$ref": "#/components/schemas/EventLead"
					},
					"sender": {
						"$ref": "#/components/schemas/EventSender"
					},
					"invitedAt": {
						"type": "string",
						"format": "date-time"
					},
					"acceptedAt": {
						"type": "string",
						"format": "date-time"
					},
					"previousSenderId": {
						"type": "string",
						"description": "Present when they accepted a second-chance invitation: the enrollment moved from this sender to `senderId`, which sends the next steps and owns the conversation."
					}
				},
				"required": [
					"enrollmentId",
					"campaignId",
					"leadId",
					"senderId",
					"campaign",
					"lead",
					"sender",
					"acceptedAt"
				],
				"additionalProperties": false
			},
			"LeadInviteWithdrawnEventData": {
				"type": "object",
				"properties": {
					"enrollmentId": {
						"type": "string",
						"description": "The enrollment's id.",
						"example": "enr_xA7Y99RY"
					},
					"campaignId": {
						"type": "string"
					},
					"leadId": {
						"type": "string"
					},
					"senderId": {
						"type": "string"
					},
					"campaign": {
						"$ref": "#/components/schemas/EventCampaign"
					},
					"lead": {
						"$ref": "#/components/schemas/EventLead"
					},
					"sender": {
						"$ref": "#/components/schemas/EventSender"
					},
					"invitedAt": {
						"type": "string",
						"format": "date-time"
					},
					"acceptanceWindowDays": {
						"type": "integer"
					},
					"reason": {
						"type": "string",
						"enum": ["window_ended", "connected_elsewhere"],
						"description": "window_ended: nobody's invitation was accepted in time (the lead completes with not_accepted). connected_elsewhere: they connected with another sender of the enrollment, so this sender's (`senderId`) pending invitation was taken back."
					}
				},
				"required": [
					"enrollmentId",
					"campaignId",
					"leadId",
					"senderId",
					"campaign",
					"lead",
					"sender",
					"acceptanceWindowDays"
				],
				"additionalProperties": false
			},
			"LeadMessageSentEventData": {
				"type": "object",
				"properties": {
					"enrollmentId": {
						"type": "string",
						"description": "The enrollment's id.",
						"example": "enr_xA7Y99RY"
					},
					"campaignId": {
						"type": "string"
					},
					"leadId": {
						"type": "string"
					},
					"senderId": {
						"type": "string"
					},
					"campaign": {
						"$ref": "#/components/schemas/EventCampaign"
					},
					"lead": {
						"$ref": "#/components/schemas/EventLead"
					},
					"sender": {
						"$ref": "#/components/schemas/EventSender"
					},
					"stepIndex": {
						"type": "integer",
						"description": "The step of the sequence (0-based)."
					},
					"text": {
						"type": "string"
					},
					"conversationId": {
						"type": "string"
					},
					"messageId": {
						"type": "string",
						"description": "The message in the conversation (GET /v1/conversations/{id}).",
						"example": "msg_3kD9xQ"
					},
					"providerMessageId": {
						"type": "string",
						"description": "LinkedIn's id for the message (through our provider), when it gave one: the same message always carries the same one, so it deduplicates across sources."
					}
				},
				"required": [
					"enrollmentId",
					"campaignId",
					"leadId",
					"senderId",
					"campaign",
					"lead",
					"sender",
					"stepIndex",
					"text",
					"conversationId"
				],
				"additionalProperties": false
			},
			"LeadRepliedEventData": {
				"type": "object",
				"properties": {
					"enrollmentId": {
						"type": "string",
						"description": "The enrollment's id.",
						"example": "enr_xA7Y99RY"
					},
					"campaignId": {
						"type": "string"
					},
					"leadId": {
						"type": "string"
					},
					"senderId": {
						"type": "string"
					},
					"campaign": {
						"$ref": "#/components/schemas/EventCampaign"
					},
					"lead": {
						"$ref": "#/components/schemas/EventLead"
					},
					"sender": {
						"$ref": "#/components/schemas/EventSender"
					},
					"text": {
						"type": "string"
					},
					"conversationId": {
						"type": "string"
					},
					"messageId": {
						"type": "string"
					},
					"providerMessageId": {
						"type": "string",
						"description": "LinkedIn's id for the message (through our provider), when it gave one: the same message always carries the same one, so it deduplicates across sources."
					},
					"sequenceFinished": {
						"type": "boolean",
						"description": "true when they replied after their sequence had already completed."
					}
				},
				"required": [
					"enrollmentId",
					"campaignId",
					"leadId",
					"senderId",
					"campaign",
					"lead",
					"sender",
					"text",
					"conversationId",
					"messageId",
					"sequenceFinished"
				],
				"additionalProperties": false
			},
			"LeadCompletedEventData": {
				"type": "object",
				"properties": {
					"enrollmentId": {
						"type": "string",
						"description": "The enrollment's id.",
						"example": "enr_xA7Y99RY"
					},
					"campaignId": {
						"type": "string"
					},
					"leadId": {
						"type": "string"
					},
					"senderId": {
						"type": "string"
					},
					"campaign": {
						"$ref": "#/components/schemas/EventCampaign"
					},
					"lead": {
						"$ref": "#/components/schemas/EventLead"
					},
					"sender": {
						"$ref": "#/components/schemas/EventSender"
					},
					"stopReason": {
						"type": "string",
						"enum": [
							"blocklisted",
							"already_in_campaign",
							"missing_variable",
							"note_too_long",
							"message_too_long",
							"not_connected",
							"not_accepted",
							"not_found",
							"cannot_invite",
							"linkedin_error",
							"stopped_by_user",
							"campaign_archived",
							"already_connected"
						],
						"description": "Absent when the whole sequence ran; not_accepted when the invitation was withdrawn unanswered."
					}
				},
				"required": [
					"enrollmentId",
					"campaignId",
					"leadId",
					"senderId",
					"campaign",
					"lead",
					"sender"
				],
				"additionalProperties": false
			},
			"LeadFailedEventData": {
				"type": "object",
				"properties": {
					"enrollmentId": {
						"type": "string",
						"description": "The enrollment's id.",
						"example": "enr_xA7Y99RY"
					},
					"campaignId": {
						"type": "string"
					},
					"leadId": {
						"type": "string"
					},
					"senderId": {
						"type": "string"
					},
					"campaign": {
						"$ref": "#/components/schemas/EventCampaign"
					},
					"lead": {
						"$ref": "#/components/schemas/EventLead"
					},
					"sender": {
						"$ref": "#/components/schemas/EventSender"
					},
					"stopReason": {
						"type": "string",
						"enum": [
							"blocklisted",
							"already_in_campaign",
							"missing_variable",
							"note_too_long",
							"message_too_long",
							"not_connected",
							"not_accepted",
							"not_found",
							"cannot_invite",
							"linkedin_error",
							"stopped_by_user",
							"campaign_archived",
							"already_connected"
						]
					},
					"detail": {
						"type": "string"
					}
				},
				"required": [
					"enrollmentId",
					"campaignId",
					"leadId",
					"senderId",
					"campaign",
					"lead",
					"sender",
					"stopReason",
					"detail"
				],
				"additionalProperties": false
			},
			"MessageReceivedEventData": {
				"type": "object",
				"properties": {
					"conversationId": {
						"type": "string"
					},
					"messageId": {
						"type": "string"
					},
					"providerMessageId": {
						"type": "string",
						"description": "LinkedIn's id for the message (through our provider), when it gave one: the same message always carries the same one, so it deduplicates across sources."
					},
					"senderId": {
						"type": "string"
					},
					"leadId": {
						"type": "string"
					},
					"text": {
						"type": "string"
					},
					"sentAt": {
						"type": "string",
						"format": "date-time"
					},
					"sender": {
						"$ref": "#/components/schemas/EventSender"
					},
					"lead": {
						"$ref": "#/components/schemas/EventLead"
					},
					"campaign": {
						"$ref": "#/components/schemas/EventCampaign"
					}
				},
				"required": [
					"conversationId",
					"messageId",
					"senderId",
					"leadId",
					"text",
					"sentAt",
					"sender",
					"lead"
				],
				"additionalProperties": false
			},
			"CampaignArchivedEventData": {
				"type": "object",
				"properties": {
					"campaignId": {
						"type": "string",
						"description": "The campaign's id.",
						"example": "cmp_pToocdWF"
					},
					"campaign": {
						"$ref": "#/components/schemas/EventCampaign"
					},
					"stopped": {
						"type": "integer",
						"description": "Live enrollments stopped by the archive (each also emits lead.stopped with stopReason campaign_archived)."
					}
				},
				"required": ["campaignId", "campaign", "stopped"],
				"additionalProperties": false
			},
			"LeadStoppedEventData": {
				"type": "object",
				"properties": {
					"enrollmentId": {
						"type": "string",
						"description": "The enrollment's id.",
						"example": "enr_xA7Y99RY"
					},
					"campaignId": {
						"type": "string"
					},
					"leadId": {
						"type": "string"
					},
					"senderId": {
						"type": "string"
					},
					"campaign": {
						"$ref": "#/components/schemas/EventCampaign"
					},
					"lead": {
						"$ref": "#/components/schemas/EventLead"
					},
					"sender": {
						"$ref": "#/components/schemas/EventSender"
					},
					"stopReason": {
						"type": "string",
						"enum": [
							"blocklisted",
							"already_in_campaign",
							"missing_variable",
							"note_too_long",
							"message_too_long",
							"not_connected",
							"not_accepted",
							"not_found",
							"cannot_invite",
							"linkedin_error",
							"stopped_by_user",
							"campaign_archived",
							"already_connected"
						],
						"description": "stopped_by_user (POST …/enrollments/{id}/stop) or campaign_archived."
					}
				},
				"required": [
					"enrollmentId",
					"campaignId",
					"leadId",
					"senderId",
					"campaign",
					"lead",
					"sender",
					"stopReason"
				],
				"additionalProperties": false
			},
			"LeadDeletedEventData": {
				"type": "object",
				"properties": {
					"leadId": {
						"type": "string",
						"description": "The deleted lead's id.",
						"example": "lead_kLkaq0WP"
					}
				},
				"required": ["leadId"],
				"additionalProperties": false
			},
			"LeadConnectedEventData": {
				"type": "object",
				"properties": {
					"leadId": {
						"type": "string"
					},
					"senderId": {
						"type": "string"
					},
					"lead": {
						"$ref": "#/components/schemas/EventLead"
					},
					"sender": {
						"$ref": "#/components/schemas/EventSender"
					},
					"connectedAt": {
						"type": "string",
						"format": "date-time"
					},
					"alreadyConnected": {
						"type": "boolean",
						"description": "true when a profile lookup found them connected already (before this sender invited them, or connected outside Outvoy); false when LinkedIn reported a new connection."
					},
					"enrollmentId": {
						"type": "string",
						"description": "The enrollment this connection concerns: the one whose invitation it answers (also after that enrollment ended), or the live one it changes."
					},
					"campaignId": {
						"type": "string"
					},
					"campaign": {
						"$ref": "#/components/schemas/EventCampaign"
					},
					"previousSenderId": {
						"type": "string",
						"description": "Present when this connection made `senderId` the enrollment's sender (a second-chance sender found them connected already, ifAlreadyConnected = continue): the enrollment moved from this sender."
					}
				},
				"required": [
					"leadId",
					"senderId",
					"lead",
					"sender",
					"connectedAt",
					"alreadyConnected"
				],
				"additionalProperties": false
			},
			"MessageSentEventData": {
				"type": "object",
				"properties": {
					"conversationId": {
						"type": "string"
					},
					"messageId": {
						"type": "string"
					},
					"providerMessageId": {
						"type": "string",
						"description": "LinkedIn's id for the message (through our provider), when it gave one: the same message always carries the same one, so it deduplicates across sources."
					},
					"senderId": {
						"type": "string"
					},
					"leadId": {
						"type": "string"
					},
					"text": {
						"type": "string"
					},
					"sentAt": {
						"type": "string",
						"format": "date-time"
					},
					"source": {
						"type": "string",
						"enum": ["inbox", "manual"],
						"description": "inbox: sent through Outvoy (API, console, MCP). manual: written by the account's owner on LinkedIn. Messages sent by sequence steps are lead.message_sent instead."
					},
					"sender": {
						"$ref": "#/components/schemas/EventSender"
					},
					"lead": {
						"$ref": "#/components/schemas/EventLead"
					},
					"campaign": {
						"$ref": "#/components/schemas/EventCampaign"
					}
				},
				"required": [
					"conversationId",
					"messageId",
					"senderId",
					"leadId",
					"text",
					"sentAt",
					"source",
					"sender",
					"lead"
				],
				"additionalProperties": false
			},
			"Error": {
				"type": "object",
				"properties": {
					"message": {
						"type": "string"
					},
					"errorCode": {
						"type": "string",
						"enum": [
							"ALREADY_SUBSCRIBED_ERROR",
							"API_KEY_ALREADY_REVOKED_ERROR",
							"APPSUMO_NOT_CONFIGURED_ERROR",
							"APPSUMO_REQUEST_FAILED_ERROR",
							"BILLING_NOT_CONFIGURED_ERROR",
							"BILLING_PROVIDER_REQUEST_FAILED_ERROR",
							"CAMPAIGN_LAUNCH_BLOCKED_ERROR",
							"CAMPAIGN_NOT_EDITABLE_ERROR",
							"CAMPAIGN_STATUS_CONFLICT_ERROR",
							"COMP_PLAN_EXPIRY_IN_PAST_ERROR",
							"COMP_PLAN_NOT_FOUND_ERROR",
							"CONNECT_LINK_ALREADY_USED_ERROR",
							"CONNECT_LINK_NOT_FOUND_ERROR",
							"DATA_EXPORT_IN_PROGRESS_ERROR",
							"DATA_EXPORT_LINK_INVALID_ERROR",
							"DATA_EXPORT_NOT_READY_ERROR",
							"EMAIL_ALREADY_REGISTERED_ERROR",
							"ENROLLMENT_NOT_LIVE_ERROR",
							"ENTITY_LOCK_CONTENTION_ERROR",
							"ENTITY_LOCK_OWNERSHIP_LOST_ERROR",
							"ENTITY_LOCK_REENTRANT_ERROR",
							"ENTITY_NOT_FOUND",
							"EXTRA_SENDERS_BELOW_CONNECTED_ERROR",
							"EXTRA_SENDERS_NOT_CONFIGURED_ERROR",
							"EXTRA_SENDERS_NOT_OFFERED_ERROR",
							"IDEMPOTENCY_KEY_REUSED_ERROR",
							"INVALID_ARGUMENT_ERROR",
							"INVALID_CAMPAIGN_SEQUENCE_ERROR",
							"INVALID_CREDENTIALS_ERROR",
							"INVALID_LINKEDIN_PROFILE_ERROR",
							"INVALID_REPOSITORY_ROW",
							"INVALID_WEBHOOK_URL_ERROR",
							"LICENSE_ALREADY_ACTIVE_ERROR",
							"LICENSE_ALREADY_ATTACHED_ERROR",
							"LICENSE_NOT_REDEEMABLE_ERROR",
							"LICENSE_REDEEM_TOKEN_INVALID_ERROR",
							"LICENSE_STACKING_NOT_ALLOWED_ERROR",
							"LICENSE_TIER_UNKNOWN_ERROR",
							"LINKEDIN_ACCOUNT_ALREADY_CONNECTED_ERROR",
							"LINKEDIN_ACCOUNT_NOT_FOUND_ERROR",
							"LINKEDIN_ACCOUNT_NOT_READY_ERROR",
							"LINKEDIN_ACTION_FAILED_ERROR",
							"LINKEDIN_NOT_CONFIGURED_ERROR",
							"LINKEDIN_REQUEST_FAILED_ERROR",
							"NO_BILLING_ACCOUNT_ERROR",
							"PLAN_LIMIT_REACHED_ERROR",
							"PLAN_REQUIRED_ERROR",
							"SENDER_DAILY_MESSAGE_CAP_REACHED_ERROR",
							"SENDER_LIMIT_EXCEEDED_ERROR",
							"SENDER_NOT_ACTIVE_ERROR",
							"SENDER_NOT_RECONNECTABLE_ERROR",
							"SESSION_REQUIRED_ERROR",
							"TOO_MANY_ATTEMPTS_ERROR",
							"TRANSACTION_ONLY_VALID_WITH_ASYNC_LOCAL_STORAGE_CLIENT",
							"UNAUTHORIZED",
							"UNEXPECTED_ERROR",
							"UNPROCESSABLE_CONTENT",
							"WEBHOOK_ENDPOINT_LIMIT_REACHED_ERROR",
							"WORKSPACE_DELETION_BLOCKED_ERROR",
							"WORKSPACE_NAME_MISMATCH_ERROR",
							"WORKSPACE_OWNER_NOT_FOUND_ERROR",
							"WORKSPACE_OWNER_REQUIRED_ERROR"
						]
					},
					"details": {
						"type": "object",
						"additionalProperties": {}
					}
				},
				"required": ["message", "errorCode"]
			}
		},
		"responses": {
			"Unauthorized": {
				"description": "Missing, invalid or revoked API key or session. Never carries WWW-Authenticate.",
				"content": {
					"application/json": {
						"schema": {
							"$ref": "#/components/schemas/Error"
						}
					}
				}
			},
			"PaymentRequired": {
				"description": "The plan's limit is reached (PLAN_LIMIT_REACHED_ERROR); the message names the plan that allows more.",
				"content": {
					"application/json": {
						"schema": {
							"$ref": "#/components/schemas/Error"
						}
					}
				}
			},
			"Forbidden": {
				"description": "The caller may not do this (e.g. an API key calling a console-session-only route).",
				"content": {
					"application/json": {
						"schema": {
							"$ref": "#/components/schemas/Error"
						}
					}
				}
			},
			"NotFound": {
				"description": "The resource does not exist in this workspace.",
				"content": {
					"application/json": {
						"schema": {
							"$ref": "#/components/schemas/Error"
						}
					}
				}
			},
			"Conflict": {
				"description": "The resource is not in a state that allows this (e.g. editing the steps of a running campaign).",
				"content": {
					"application/json": {
						"schema": {
							"$ref": "#/components/schemas/Error"
						}
					}
				}
			},
			"UnprocessableContent": {
				"description": "The input is invalid. For a validation failure `message` names the first problem and `details.issues` lists every one as `{ path, message, code }`; unknown fields are refused, not ignored. Some business rules answer 422 too, with their own errorCode and details.",
				"content": {
					"application/json": {
						"schema": {
							"$ref": "#/components/schemas/Error"
						}
					}
				}
			},
			"TooManyRequests": {
				"description": "Too many attempts; retry later.",
				"content": {
					"application/json": {
						"schema": {
							"$ref": "#/components/schemas/Error"
						}
					}
				}
			},
			"ServiceUnavailable": {
				"description": "A dependency this route needs is not configured or not reachable (e.g. no LinkedIn provider: use a sandbox sender).",
				"content": {
					"application/json": {
						"schema": {
							"$ref": "#/components/schemas/Error"
						}
					}
				}
			}
		},
		"parameters": {
			"IdempotencyKey": {
				"name": "Idempotency-Key",
				"in": "header",
				"required": false,
				"description": "Any string up to 200 characters. The first 2xx answer is stored for 24 hours for this caller, method and path and replayed (header `Idempotent-Replayed: true`) when the same key comes back with the same body; the same key with a different body is refused with 422 IDEMPOTENCY_KEY_REUSED_ERROR.",
				"schema": {
					"type": "string",
					"maxLength": 200
				}
			}
		},
		"securitySchemes": {
			"bearerAuth": {
				"type": "http",
				"scheme": "bearer",
				"bearerFormat": "API key (ov_…) or console session"
			}
		}
	},
	"webhooks": {
		"sender.connected": {
			"post": {
				"operationId": "senderConnectedEvent",
				"summary": "sender.connected",
				"tags": ["Events"],
				"description": "Delivered to every enabled webhook endpoint that wants sender.connected, signed with Outvoy-Signature; the same object is an item of GET /v1/events.",
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"type": "object",
								"properties": {
									"id": {
										"type": "string",
										"example": "evt_01JB8Y2K7Q3W9E5R1T6Y4U0I2O"
									},
									"type": {
										"type": "string",
										"const": "sender.connected"
									},
									"occurredAt": {
										"type": "string",
										"format": "date-time"
									},
									"data": {
										"$ref": "#/components/schemas/SenderConnectedEventData"
									}
								},
								"required": ["id", "type", "occurredAt", "data"]
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Any 2xx within 10 s acknowledges; anything else is retried."
					}
				}
			}
		},
		"sender.needs_reconnect": {
			"post": {
				"operationId": "senderNeedsReconnectEvent",
				"summary": "sender.needs_reconnect",
				"tags": ["Events"],
				"description": "Delivered to every enabled webhook endpoint that wants sender.needs_reconnect, signed with Outvoy-Signature; the same object is an item of GET /v1/events.",
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"type": "object",
								"properties": {
									"id": {
										"type": "string",
										"example": "evt_01JB8Y2K7Q3W9E5R1T6Y4U0I2O"
									},
									"type": {
										"type": "string",
										"const": "sender.needs_reconnect"
									},
									"occurredAt": {
										"type": "string",
										"format": "date-time"
									},
									"data": {
										"$ref": "#/components/schemas/SenderNeedsReconnectEventData"
									}
								},
								"required": ["id", "type", "occurredAt", "data"]
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Any 2xx within 10 s acknowledges; anything else is retried."
					}
				}
			}
		},
		"sender.paused": {
			"post": {
				"operationId": "senderPausedEvent",
				"summary": "sender.paused",
				"tags": ["Events"],
				"description": "Delivered to every enabled webhook endpoint that wants sender.paused, signed with Outvoy-Signature; the same object is an item of GET /v1/events.",
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"type": "object",
								"properties": {
									"id": {
										"type": "string",
										"example": "evt_01JB8Y2K7Q3W9E5R1T6Y4U0I2O"
									},
									"type": {
										"type": "string",
										"const": "sender.paused"
									},
									"occurredAt": {
										"type": "string",
										"format": "date-time"
									},
									"data": {
										"$ref": "#/components/schemas/SenderEventData"
									}
								},
								"required": ["id", "type", "occurredAt", "data"]
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Any 2xx within 10 s acknowledges; anything else is retried."
					}
				}
			}
		},
		"sender.resumed": {
			"post": {
				"operationId": "senderResumedEvent",
				"summary": "sender.resumed",
				"tags": ["Events"],
				"description": "Delivered to every enabled webhook endpoint that wants sender.resumed, signed with Outvoy-Signature; the same object is an item of GET /v1/events.",
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"type": "object",
								"properties": {
									"id": {
										"type": "string",
										"example": "evt_01JB8Y2K7Q3W9E5R1T6Y4U0I2O"
									},
									"type": {
										"type": "string",
										"const": "sender.resumed"
									},
									"occurredAt": {
										"type": "string",
										"format": "date-time"
									},
									"data": {
										"$ref": "#/components/schemas/SenderEventData"
									}
								},
								"required": ["id", "type", "occurredAt", "data"]
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Any 2xx within 10 s acknowledges; anything else is retried."
					}
				}
			}
		},
		"import.completed": {
			"post": {
				"operationId": "importCompletedEvent",
				"summary": "import.completed",
				"tags": ["Events"],
				"description": "Delivered to every enabled webhook endpoint that wants import.completed, signed with Outvoy-Signature; the same object is an item of GET /v1/events.",
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"type": "object",
								"properties": {
									"id": {
										"type": "string",
										"example": "evt_01JB8Y2K7Q3W9E5R1T6Y4U0I2O"
									},
									"type": {
										"type": "string",
										"const": "import.completed"
									},
									"occurredAt": {
										"type": "string",
										"format": "date-time"
									},
									"data": {
										"$ref": "#/components/schemas/ImportEventData"
									}
								},
								"required": ["id", "type", "occurredAt", "data"]
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Any 2xx within 10 s acknowledges; anything else is retried."
					}
				}
			}
		},
		"import.failed": {
			"post": {
				"operationId": "importFailedEvent",
				"summary": "import.failed",
				"tags": ["Events"],
				"description": "Delivered to every enabled webhook endpoint that wants import.failed, signed with Outvoy-Signature; the same object is an item of GET /v1/events.",
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"type": "object",
								"properties": {
									"id": {
										"type": "string",
										"example": "evt_01JB8Y2K7Q3W9E5R1T6Y4U0I2O"
									},
									"type": {
										"type": "string",
										"const": "import.failed"
									},
									"occurredAt": {
										"type": "string",
										"format": "date-time"
									},
									"data": {
										"$ref": "#/components/schemas/ImportEventData"
									}
								},
								"required": ["id", "type", "occurredAt", "data"]
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Any 2xx within 10 s acknowledges; anything else is retried."
					}
				}
			}
		},
		"campaign.launched": {
			"post": {
				"operationId": "campaignLaunchedEvent",
				"summary": "campaign.launched",
				"tags": ["Events"],
				"description": "Delivered to every enabled webhook endpoint that wants campaign.launched, signed with Outvoy-Signature; the same object is an item of GET /v1/events.",
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"type": "object",
								"properties": {
									"id": {
										"type": "string",
										"example": "evt_01JB8Y2K7Q3W9E5R1T6Y4U0I2O"
									},
									"type": {
										"type": "string",
										"const": "campaign.launched"
									},
									"occurredAt": {
										"type": "string",
										"format": "date-time"
									},
									"data": {
										"$ref": "#/components/schemas/CampaignLaunchedEventData"
									}
								},
								"required": ["id", "type", "occurredAt", "data"]
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Any 2xx within 10 s acknowledges; anything else is retried."
					}
				}
			}
		},
		"campaign.paused": {
			"post": {
				"operationId": "campaignPausedEvent",
				"summary": "campaign.paused",
				"tags": ["Events"],
				"description": "Delivered to every enabled webhook endpoint that wants campaign.paused, signed with Outvoy-Signature; the same object is an item of GET /v1/events.",
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"type": "object",
								"properties": {
									"id": {
										"type": "string",
										"example": "evt_01JB8Y2K7Q3W9E5R1T6Y4U0I2O"
									},
									"type": {
										"type": "string",
										"const": "campaign.paused"
									},
									"occurredAt": {
										"type": "string",
										"format": "date-time"
									},
									"data": {
										"$ref": "#/components/schemas/CampaignEventData"
									}
								},
								"required": ["id", "type", "occurredAt", "data"]
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Any 2xx within 10 s acknowledges; anything else is retried."
					}
				}
			}
		},
		"campaign.resumed": {
			"post": {
				"operationId": "campaignResumedEvent",
				"summary": "campaign.resumed",
				"tags": ["Events"],
				"description": "Delivered to every enabled webhook endpoint that wants campaign.resumed, signed with Outvoy-Signature; the same object is an item of GET /v1/events.",
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"type": "object",
								"properties": {
									"id": {
										"type": "string",
										"example": "evt_01JB8Y2K7Q3W9E5R1T6Y4U0I2O"
									},
									"type": {
										"type": "string",
										"const": "campaign.resumed"
									},
									"occurredAt": {
										"type": "string",
										"format": "date-time"
									},
									"data": {
										"$ref": "#/components/schemas/CampaignEventData"
									}
								},
								"required": ["id", "type", "occurredAt", "data"]
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Any 2xx within 10 s acknowledges; anything else is retried."
					}
				}
			}
		},
		"campaign.completed": {
			"post": {
				"operationId": "campaignCompletedEvent",
				"summary": "campaign.completed",
				"tags": ["Events"],
				"description": "Delivered to every enabled webhook endpoint that wants campaign.completed, signed with Outvoy-Signature; the same object is an item of GET /v1/events.",
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"type": "object",
								"properties": {
									"id": {
										"type": "string",
										"example": "evt_01JB8Y2K7Q3W9E5R1T6Y4U0I2O"
									},
									"type": {
										"type": "string",
										"const": "campaign.completed"
									},
									"occurredAt": {
										"type": "string",
										"format": "date-time"
									},
									"data": {
										"$ref": "#/components/schemas/CampaignEventData"
									}
								},
								"required": ["id", "type", "occurredAt", "data"]
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Any 2xx within 10 s acknowledges; anything else is retried."
					}
				}
			}
		},
		"lead.enrolled": {
			"post": {
				"operationId": "leadEnrolledEvent",
				"summary": "lead.enrolled",
				"tags": ["Events"],
				"description": "Delivered to every enabled webhook endpoint that wants lead.enrolled, signed with Outvoy-Signature; the same object is an item of GET /v1/events.",
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"type": "object",
								"properties": {
									"id": {
										"type": "string",
										"example": "evt_01JB8Y2K7Q3W9E5R1T6Y4U0I2O"
									},
									"type": {
										"type": "string",
										"const": "lead.enrolled"
									},
									"occurredAt": {
										"type": "string",
										"format": "date-time"
									},
									"data": {
										"$ref": "#/components/schemas/LeadEventData"
									}
								},
								"required": ["id", "type", "occurredAt", "data"]
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Any 2xx within 10 s acknowledges; anything else is retried."
					}
				}
			}
		},
		"lead.profile_visited": {
			"post": {
				"operationId": "leadProfileVisitedEvent",
				"summary": "lead.profile_visited",
				"tags": ["Events"],
				"description": "Delivered to every enabled webhook endpoint that wants lead.profile_visited, signed with Outvoy-Signature; the same object is an item of GET /v1/events.",
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"type": "object",
								"properties": {
									"id": {
										"type": "string",
										"example": "evt_01JB8Y2K7Q3W9E5R1T6Y4U0I2O"
									},
									"type": {
										"type": "string",
										"const": "lead.profile_visited"
									},
									"occurredAt": {
										"type": "string",
										"format": "date-time"
									},
									"data": {
										"$ref": "#/components/schemas/LeadProfileVisitedEventData"
									}
								},
								"required": ["id", "type", "occurredAt", "data"]
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Any 2xx within 10 s acknowledges; anything else is retried."
					}
				}
			}
		},
		"lead.post_liked": {
			"post": {
				"operationId": "leadPostLikedEvent",
				"summary": "lead.post_liked",
				"tags": ["Events"],
				"description": "Delivered to every enabled webhook endpoint that wants lead.post_liked, signed with Outvoy-Signature; the same object is an item of GET /v1/events.",
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"type": "object",
								"properties": {
									"id": {
										"type": "string",
										"example": "evt_01JB8Y2K7Q3W9E5R1T6Y4U0I2O"
									},
									"type": {
										"type": "string",
										"const": "lead.post_liked"
									},
									"occurredAt": {
										"type": "string",
										"format": "date-time"
									},
									"data": {
										"$ref": "#/components/schemas/LeadPostLikedEventData"
									}
								},
								"required": ["id", "type", "occurredAt", "data"]
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Any 2xx within 10 s acknowledges; anything else is retried."
					}
				}
			}
		},
		"lead.invite_sent": {
			"post": {
				"operationId": "leadInviteSentEvent",
				"summary": "lead.invite_sent",
				"tags": ["Events"],
				"description": "Delivered to every enabled webhook endpoint that wants lead.invite_sent, signed with Outvoy-Signature; the same object is an item of GET /v1/events.",
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"type": "object",
								"properties": {
									"id": {
										"type": "string",
										"example": "evt_01JB8Y2K7Q3W9E5R1T6Y4U0I2O"
									},
									"type": {
										"type": "string",
										"const": "lead.invite_sent"
									},
									"occurredAt": {
										"type": "string",
										"format": "date-time"
									},
									"data": {
										"$ref": "#/components/schemas/LeadInviteSentEventData"
									}
								},
								"required": ["id", "type", "occurredAt", "data"]
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Any 2xx within 10 s acknowledges; anything else is retried."
					}
				}
			}
		},
		"lead.invite_accepted": {
			"post": {
				"operationId": "leadInviteAcceptedEvent",
				"summary": "lead.invite_accepted",
				"tags": ["Events"],
				"description": "Delivered to every enabled webhook endpoint that wants lead.invite_accepted, signed with Outvoy-Signature; the same object is an item of GET /v1/events.",
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"type": "object",
								"properties": {
									"id": {
										"type": "string",
										"example": "evt_01JB8Y2K7Q3W9E5R1T6Y4U0I2O"
									},
									"type": {
										"type": "string",
										"const": "lead.invite_accepted"
									},
									"occurredAt": {
										"type": "string",
										"format": "date-time"
									},
									"data": {
										"$ref": "#/components/schemas/LeadInviteAcceptedEventData"
									}
								},
								"required": ["id", "type", "occurredAt", "data"]
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Any 2xx within 10 s acknowledges; anything else is retried."
					}
				}
			}
		},
		"lead.invite_withdrawn": {
			"post": {
				"operationId": "leadInviteWithdrawnEvent",
				"summary": "lead.invite_withdrawn",
				"tags": ["Events"],
				"description": "Delivered to every enabled webhook endpoint that wants lead.invite_withdrawn, signed with Outvoy-Signature; the same object is an item of GET /v1/events.",
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"type": "object",
								"properties": {
									"id": {
										"type": "string",
										"example": "evt_01JB8Y2K7Q3W9E5R1T6Y4U0I2O"
									},
									"type": {
										"type": "string",
										"const": "lead.invite_withdrawn"
									},
									"occurredAt": {
										"type": "string",
										"format": "date-time"
									},
									"data": {
										"$ref": "#/components/schemas/LeadInviteWithdrawnEventData"
									}
								},
								"required": ["id", "type", "occurredAt", "data"]
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Any 2xx within 10 s acknowledges; anything else is retried."
					}
				}
			}
		},
		"lead.message_sent": {
			"post": {
				"operationId": "leadMessageSentEvent",
				"summary": "lead.message_sent",
				"tags": ["Events"],
				"description": "Delivered to every enabled webhook endpoint that wants lead.message_sent, signed with Outvoy-Signature; the same object is an item of GET /v1/events.",
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"type": "object",
								"properties": {
									"id": {
										"type": "string",
										"example": "evt_01JB8Y2K7Q3W9E5R1T6Y4U0I2O"
									},
									"type": {
										"type": "string",
										"const": "lead.message_sent"
									},
									"occurredAt": {
										"type": "string",
										"format": "date-time"
									},
									"data": {
										"$ref": "#/components/schemas/LeadMessageSentEventData"
									}
								},
								"required": ["id", "type", "occurredAt", "data"]
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Any 2xx within 10 s acknowledges; anything else is retried."
					}
				}
			}
		},
		"lead.replied": {
			"post": {
				"operationId": "leadRepliedEvent",
				"summary": "lead.replied",
				"tags": ["Events"],
				"description": "Delivered to every enabled webhook endpoint that wants lead.replied, signed with Outvoy-Signature; the same object is an item of GET /v1/events.",
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"type": "object",
								"properties": {
									"id": {
										"type": "string",
										"example": "evt_01JB8Y2K7Q3W9E5R1T6Y4U0I2O"
									},
									"type": {
										"type": "string",
										"const": "lead.replied"
									},
									"occurredAt": {
										"type": "string",
										"format": "date-time"
									},
									"data": {
										"$ref": "#/components/schemas/LeadRepliedEventData"
									}
								},
								"required": ["id", "type", "occurredAt", "data"]
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Any 2xx within 10 s acknowledges; anything else is retried."
					}
				}
			}
		},
		"lead.completed": {
			"post": {
				"operationId": "leadCompletedEvent",
				"summary": "lead.completed",
				"tags": ["Events"],
				"description": "Delivered to every enabled webhook endpoint that wants lead.completed, signed with Outvoy-Signature; the same object is an item of GET /v1/events.",
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"type": "object",
								"properties": {
									"id": {
										"type": "string",
										"example": "evt_01JB8Y2K7Q3W9E5R1T6Y4U0I2O"
									},
									"type": {
										"type": "string",
										"const": "lead.completed"
									},
									"occurredAt": {
										"type": "string",
										"format": "date-time"
									},
									"data": {
										"$ref": "#/components/schemas/LeadCompletedEventData"
									}
								},
								"required": ["id", "type", "occurredAt", "data"]
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Any 2xx within 10 s acknowledges; anything else is retried."
					}
				}
			}
		},
		"lead.failed": {
			"post": {
				"operationId": "leadFailedEvent",
				"summary": "lead.failed",
				"tags": ["Events"],
				"description": "Delivered to every enabled webhook endpoint that wants lead.failed, signed with Outvoy-Signature; the same object is an item of GET /v1/events.",
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"type": "object",
								"properties": {
									"id": {
										"type": "string",
										"example": "evt_01JB8Y2K7Q3W9E5R1T6Y4U0I2O"
									},
									"type": {
										"type": "string",
										"const": "lead.failed"
									},
									"occurredAt": {
										"type": "string",
										"format": "date-time"
									},
									"data": {
										"$ref": "#/components/schemas/LeadFailedEventData"
									}
								},
								"required": ["id", "type", "occurredAt", "data"]
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Any 2xx within 10 s acknowledges; anything else is retried."
					}
				}
			}
		},
		"message.received": {
			"post": {
				"operationId": "messageReceivedEvent",
				"summary": "message.received",
				"tags": ["Events"],
				"description": "Delivered to every enabled webhook endpoint that wants message.received, signed with Outvoy-Signature; the same object is an item of GET /v1/events.",
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"type": "object",
								"properties": {
									"id": {
										"type": "string",
										"example": "evt_01JB8Y2K7Q3W9E5R1T6Y4U0I2O"
									},
									"type": {
										"type": "string",
										"const": "message.received"
									},
									"occurredAt": {
										"type": "string",
										"format": "date-time"
									},
									"data": {
										"$ref": "#/components/schemas/MessageReceivedEventData"
									}
								},
								"required": ["id", "type", "occurredAt", "data"]
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Any 2xx within 10 s acknowledges; anything else is retried."
					}
				}
			}
		},
		"campaign.archived": {
			"post": {
				"operationId": "campaignArchivedEvent",
				"summary": "campaign.archived",
				"tags": ["Events"],
				"description": "Delivered to every enabled webhook endpoint that wants campaign.archived, signed with Outvoy-Signature; the same object is an item of GET /v1/events.",
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"type": "object",
								"properties": {
									"id": {
										"type": "string",
										"example": "evt_01JB8Y2K7Q3W9E5R1T6Y4U0I2O"
									},
									"type": {
										"type": "string",
										"const": "campaign.archived"
									},
									"occurredAt": {
										"type": "string",
										"format": "date-time"
									},
									"data": {
										"$ref": "#/components/schemas/CampaignArchivedEventData"
									}
								},
								"required": ["id", "type", "occurredAt", "data"]
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Any 2xx within 10 s acknowledges; anything else is retried."
					}
				}
			}
		},
		"lead.stopped": {
			"post": {
				"operationId": "leadStoppedEvent",
				"summary": "lead.stopped",
				"tags": ["Events"],
				"description": "Delivered to every enabled webhook endpoint that wants lead.stopped, signed with Outvoy-Signature; the same object is an item of GET /v1/events.",
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"type": "object",
								"properties": {
									"id": {
										"type": "string",
										"example": "evt_01JB8Y2K7Q3W9E5R1T6Y4U0I2O"
									},
									"type": {
										"type": "string",
										"const": "lead.stopped"
									},
									"occurredAt": {
										"type": "string",
										"format": "date-time"
									},
									"data": {
										"$ref": "#/components/schemas/LeadStoppedEventData"
									}
								},
								"required": ["id", "type", "occurredAt", "data"]
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Any 2xx within 10 s acknowledges; anything else is retried."
					}
				}
			}
		},
		"lead.deleted": {
			"post": {
				"operationId": "leadDeletedEvent",
				"summary": "lead.deleted",
				"tags": ["Events"],
				"description": "Delivered to every enabled webhook endpoint that wants lead.deleted, signed with Outvoy-Signature; the same object is an item of GET /v1/events.",
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"type": "object",
								"properties": {
									"id": {
										"type": "string",
										"example": "evt_01JB8Y2K7Q3W9E5R1T6Y4U0I2O"
									},
									"type": {
										"type": "string",
										"const": "lead.deleted"
									},
									"occurredAt": {
										"type": "string",
										"format": "date-time"
									},
									"data": {
										"$ref": "#/components/schemas/LeadDeletedEventData"
									}
								},
								"required": ["id", "type", "occurredAt", "data"]
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Any 2xx within 10 s acknowledges; anything else is retried."
					}
				}
			}
		},
		"lead.connected": {
			"post": {
				"operationId": "leadConnectedEvent",
				"summary": "lead.connected",
				"tags": ["Events"],
				"description": "Delivered to every enabled webhook endpoint that wants lead.connected, signed with Outvoy-Signature; the same object is an item of GET /v1/events.",
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"type": "object",
								"properties": {
									"id": {
										"type": "string",
										"example": "evt_01JB8Y2K7Q3W9E5R1T6Y4U0I2O"
									},
									"type": {
										"type": "string",
										"const": "lead.connected"
									},
									"occurredAt": {
										"type": "string",
										"format": "date-time"
									},
									"data": {
										"$ref": "#/components/schemas/LeadConnectedEventData"
									}
								},
								"required": ["id", "type", "occurredAt", "data"]
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Any 2xx within 10 s acknowledges; anything else is retried."
					}
				}
			}
		},
		"message.sent": {
			"post": {
				"operationId": "messageSentEvent",
				"summary": "message.sent",
				"tags": ["Events"],
				"description": "Delivered to every enabled webhook endpoint that wants message.sent, signed with Outvoy-Signature; the same object is an item of GET /v1/events.",
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"type": "object",
								"properties": {
									"id": {
										"type": "string",
										"example": "evt_01JB8Y2K7Q3W9E5R1T6Y4U0I2O"
									},
									"type": {
										"type": "string",
										"const": "message.sent"
									},
									"occurredAt": {
										"type": "string",
										"format": "date-time"
									},
									"data": {
										"$ref": "#/components/schemas/MessageSentEventData"
									}
								},
								"required": ["id", "type", "occurredAt", "data"]
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Any 2xx within 10 s acknowledges; anything else is retried."
					}
				}
			}
		}
	}
}
