{
	"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.staging.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"
		},
		{
			"name": "Mailboxes"
		},
		{
			"name": "Domains"
		},
		{
			"name": "Domain orders"
		},
		{
			"name": "Deliverability"
		}
	],
	"paths": {
		"/auth/providers": {
			"get": {
				"operationId": "listSignInProviders",
				"tags": ["Auth"],
				"summary": "List the providers you can sign in with",
				"description": "Google and GitHub, each when this deployment has it configured.",
				"responses": {
					"200": {
						"description": "The providers",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/SignInProvidersOutput"
								}
							}
						}
					},
					"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"
					}
				},
				"security": [],
				"parameters": []
			}
		},
		"/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": []
			}
		},
		"/auth/providers/{provider}/start": {
			"post": {
				"operationId": "startProviderSignIn",
				"tags": ["Auth"],
				"summary": "Start signing in with Google or GitHub",
				"description": "Answers the provider's consent page for this `state` and PKCE challenge. The provider sends the browser back to the console's `/auth/callback/<provider>` with a code; check the state there, then call complete.",
				"responses": {
					"200": {
						"description": "Where to send the browser",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/StartProviderSignInOutput"
								}
							}
						}
					},
					"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": "provider",
						"in": "path",
						"required": true,
						"schema": {
							"type": "string",
							"enum": ["google", "github"]
						},
						"description": "The provider's id."
					}
				],
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/StartProviderSignInInput"
							}
						}
					}
				},
				"security": []
			}
		},
		"/auth/providers/{provider}/complete": {
			"post": {
				"operationId": "completeProviderSignIn",
				"tags": ["Auth"],
				"summary": "Finish signing in with Google or GitHub",
				"description": "Exchanges the provider's code for who signed in and returns a session. The provider account signs in as the user it is linked to; else as the account with its verified email, when that account has no password; else it creates an account and its workspace (`created: true`). An account with that email and a password is refused (409): sign in with the password.",
				"responses": {
					"200": {
						"description": "A console session (JWT, 8 hours)",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ProviderSessionOutput"
								}
							}
						}
					},
					"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": "provider",
						"in": "path",
						"required": true,
						"schema": {
							"type": "string",
							"enum": ["google", "github"]
						},
						"description": "The provider's id."
					}
				],
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/CompleteProviderSignInInput"
							}
						}
					}
				},
				"security": []
			}
		},
		"/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}/session": {
			"post": {
				"operationId": "connectLinkWithSession",
				"tags": ["Connect"],
				"summary": "Connect a LinkedIn account from the browser's session",
				"description": "Public; called by the Outvoy browser extension, never by a web page. When the account owner clicks \"Connect with one click\", the extension reads LinkedIn's `li_at` cookie from their browser and sends it here with the browser's user agent; Outvoy hands both to its LinkedIn provider, which connects (or, for a reconnect link, reconnects) the account, and the sender becomes active. The cookie is never stored or logged. 404 for unknown or expired codes, 409 when the link was already used or its sender disconnected, 422 `LINKEDIN_SESSION_INVALID_ERROR` when LinkedIn refuses the session, 409 `LINKEDIN_CHECKPOINT_REQUIRED_ERROR` when LinkedIn wants a verification (use the email-and-password page: `POST /connect/{code}/start`), 409 `LINKEDIN_ACCOUNT_ALREADY_IN_USE_ERROR` when that LinkedIn account is already connected, 503 when this server has no LinkedIn provider. Rate-limited per IP.",
				"responses": {
					"200": {
						"description": "The account is connected",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "object",
											"properties": {
												"status": {
													"type": "string",
													"enum": ["connected"],
													"description": "The LinkedIn account is connected to the sender."
												},
												"senderId": {
													"type": "string",
													"description": "The sender it connected."
												},
												"senderStatus": {
													"type": "string",
													"enum": [
														"connecting",
														"active",
														"paused",
														"needs_reconnect",
														"restricted",
														"disconnected"
													],
													"description": "`active`, or `paused` when the workspace's plan has no room for another LinkedIn sender to act."
												},
												"connectedAs": {
													"type": "string",
													"description": "The LinkedIn account's own name.",
													"example": "Ada Lovelace"
												}
											},
											"required": [
												"status",
												"senderId",
												"senderStatus",
												"connectedAs"
											]
										}
									},
									"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/ConnectWithSessionInput"
							}
						}
					}
				},
				"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",
														"trial",
														"standard",
														"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 the subscription, monthly or yearly (12 months for the price of 10), priced per connected LinkedIn account: the first $39/month, then $25, $15, $10 and $7 each. It starts with one account; connecting more adds them (charged pro rata at once once the trial is over). 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": false,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/StartCheckoutInput"
							}
						}
					}
				},
				"parameters": [
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			}
		},
		"/v1/billing/end-trial": {
			"post": {
				"operationId": "endTrial",
				"tags": ["Billing"],
				"summary": "End the free trial now (console session only)",
				"description": "For more LinkedIn accounts than the trial allows: the first charge happens now, for the accounts connected (at least 1), and the workspace moves to the paid plan when it goes through. 402 `BILLING_PAYMENT_FAILED_ERROR` when the card is declined or needs authentication: nothing changes and the trial goes on; 409 when the subscription is not in its trial; 503 when billing is not configured; 403 with an API key.",
				"responses": {
					"200": {
						"description": "The subscription's status after the charge",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "object",
											"properties": {
												"status": {
													"type": "string",
													"enum": [
														"trialing",
														"active",
														"past_due",
														"canceled",
														"incomplete"
													],
													"description": "The subscription's status once the first charge was attempted: `active` when it went through."
												}
											},
											"required": ["status"]
										}
									},
									"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/extend-trial": {
			"post": {
				"operationId": "extendTrial",
				"tags": ["Billing"],
				"summary": "Extend the free trial (console session only)",
				"description": "The cancellation flow's offer in the trial: 7 more days before the first charge, once per subscription. 409 when it was already given, the subscription isn't trialing or is set to end; 403 with an API key.",
				"responses": {
					"200": {
						"description": "The subscription after the change",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "object",
											"properties": {
												"status": {
													"type": "string",
													"enum": [
														"trialing",
														"active",
														"past_due",
														"canceled",
														"incomplete"
													]
												},
												"trialEndsAt": {
													"type": "string",
													"format": "date-time"
												},
												"cancelAtPeriodEnd": {
													"type": "boolean"
												}
											},
											"required": ["status", "cancelAtPeriodEnd"]
										}
									},
									"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/retention-discount": {
			"post": {
				"operationId": "acceptRetentionDiscount",
				"tags": ["Billing"],
				"summary": "Take the retention discount (console session only)",
				"description": "The cancellation flow's offer once paid: a discount on the next months instead of cancelling, once per subscription. 409 when it was already taken, the subscription isn't active or is set to end; 403 with an API key.",
				"responses": {
					"200": {
						"description": "The subscription after the change",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "object",
											"properties": {
												"status": {
													"type": "string",
													"enum": [
														"trialing",
														"active",
														"past_due",
														"canceled",
														"incomplete"
													]
												},
												"trialEndsAt": {
													"type": "string",
													"format": "date-time"
												},
												"cancelAtPeriodEnd": {
													"type": "boolean"
												}
											},
											"required": ["status", "cancelAtPeriodEnd"]
										}
									},
									"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/resume": {
			"post": {
				"operationId": "resumeSubscription",
				"tags": ["Billing"],
				"summary": "Keep the subscription (console session only)",
				"description": "Takes back a cancellation still pending: the subscription renews (or the trial converts) as before. 403 with an API key.",
				"responses": {
					"200": {
						"description": "The subscription after the change",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "object",
											"properties": {
												"status": {
													"type": "string",
													"enum": [
														"trialing",
														"active",
														"past_due",
														"canceled",
														"incomplete"
													]
												},
												"trialEndsAt": {
													"type": "string",
													"format": "date-time"
												},
												"cancelAtPeriodEnd": {
													"type": "boolean"
												}
											},
											"required": ["status", "cancelAtPeriodEnd"]
										}
									},
									"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/cancel": {
			"post": {
				"operationId": "cancelSubscription",
				"tags": ["Billing"],
				"summary": "Cancel the subscription (console session only)",
				"description": "Cancels at the end of the period already paid (in the trial: at its end, nothing charged), with an optional reason. The plan keeps working until then; `POST /v1/billing/resume` takes it back. 403 with an API key.",
				"responses": {
					"200": {
						"description": "The subscription after the change",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "object",
											"properties": {
												"status": {
													"type": "string",
													"enum": [
														"trialing",
														"active",
														"past_due",
														"canceled",
														"incomplete"
													]
												},
												"trialEndsAt": {
													"type": "string",
													"format": "date-time"
												},
												"cancelAtPeriodEnd": {
													"type": "boolean"
												}
											},
											"required": ["status", "cancelAtPeriodEnd"]
										}
									},
									"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/CancelSubscriptionInput"
							}
						}
					}
				},
				"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"
					}
				]
			}
		},
		"/v1/mailboxes": {
			"get": {
				"operationId": "listMailboxes",
				"tags": ["Mailboxes"],
				"summary": "List mailboxes",
				"description": "Every mailbox of the workspace except disconnected ones, oldest first: connected (your own Google, Microsoft or IMAP mailboxes), purchased through Outvoy, and sandbox ones. Each with its warm-up settings and today's numbers, working hours, its reputation (score, level, readiness and the recommended cold-email volume) and its status.",
				"responses": {
					"200": {
						"description": "The mailboxes",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "array",
											"items": {
												"$ref": "#/components/schemas/Mailbox"
											}
										}
									},
									"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/mailboxes/connect": {
			"post": {
				"operationId": "startMailboxOauth",
				"tags": ["Mailboxes"],
				"summary": "Get the sign-in link to connect a Google or Microsoft mailbox",
				"description": "Returns Google's or Microsoft's consent page (valid 10 minutes) for the mailbox's owner to open: they sign in there and allow Outvoy to send, read and organise mail (never delete), and land back in the console on the new mailbox (`mailbox.connected`). Their password never reaches Outvoy. An agent hands the URL to the human. Pass reconnectMailboxId to give a mailbox in `needs_reconnect` its access back. 402 when the plan has no connected mailbox left (or no plan); 503 when this server can't connect real mailboxes or that provider (use a sandbox mailbox). Mailboxes on other hosts connect with IMAP in the console.",
				"responses": {
					"200": {
						"description": "The consent page",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "object",
											"properties": {
												"url": {
													"type": "string",
													"format": "uri",
													"description": "Google's or Microsoft's consent page. The mailbox's owner opens it, allows Outvoy, and lands back in the console on the new mailbox. Valid for 10 minutes."
												},
												"expiresAt": {
													"type": "string",
													"format": "date-time"
												}
											},
											"required": ["url", "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": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/StartMailboxOauthInput"
							}
						}
					}
				},
				"parameters": [
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			}
		},
		"/v1/mailboxes/imap": {
			"post": {
				"operationId": "connectImapMailbox",
				"tags": ["Mailboxes"],
				"summary": "Connect a mailbox with IMAP and SMTP",
				"description": "Any host, with an app password (Gmail and Google Workspace need 2-Step Verification and an app password). Both servers must use mail ports (IMAP 993/143, SMTP 465/587/25/2525) and public addresses; Outvoy signs in to both before saving anything, so a wrong password is refused at once (422 `MAILBOX_CONNECTION_FAILED_ERROR`). The passwords are encrypted before they are stored and are never returned, logged or exported. 409 when the address is already connected to Outvoy; 402 when the plan is full.",
				"responses": {
					"200": {
						"description": "The mailbox",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/Mailbox"
										}
									},
									"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/ConnectImapMailboxInput"
							}
						}
					}
				},
				"parameters": [
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			}
		},
		"/v1/mailboxes/sandbox": {
			"post": {
				"operationId": "createSandboxMailbox",
				"tags": ["Mailboxes"],
				"summary": "Create a sandbox mailbox",
				"description": "A simulated mailbox at `<first>.<last>@<workspace>.test`, active at once and warming up in the sandbox network: its placement starts mediocre and improves day by day, like a real mailbox's. It never sends a real email. 402 when the plan's sandbox mailboxes are used up.",
				"responses": {
					"200": {
						"description": "The new mailbox",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/Mailbox"
										}
									},
									"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/CreateSandboxMailboxInput"
							}
						}
					}
				},
				"parameters": [
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			}
		},
		"/v1/mailboxes/{mailboxId}": {
			"get": {
				"operationId": "getMailbox",
				"tags": ["Mailboxes"],
				"summary": "Get a mailbox",
				"description": "One mailbox, disconnected ones included.",
				"responses": {
					"200": {
						"description": "The mailbox",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/Mailbox"
										}
									},
									"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": "mailboxId",
						"required": true,
						"description": "The mailbox's id."
					}
				]
			},
			"patch": {
				"operationId": "updateMailbox",
				"tags": ["Mailboxes"],
				"summary": "Update a mailbox's name, warm-up, working hours or cold-email cap",
				"description": "Warm-up merges over the current settings (turning it off cancels what was planned; turning it back on restarts the ramp); the schedule replaces the whole one; outreachDailyLimit null goes back to Outvoy's recommendation. 409 for a disconnected mailbox.",
				"responses": {
					"200": {
						"description": "The mailbox",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/Mailbox"
										}
									},
									"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/UpdateMailboxInput"
							}
						}
					}
				},
				"parameters": [
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "mailboxId",
						"required": true,
						"description": "The mailbox's id."
					},
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			},
			"delete": {
				"operationId": "disconnectMailbox",
				"tags": ["Mailboxes"],
				"summary": "Disconnect a mailbox",
				"description": "A connected or sandbox mailbox stops warming up for good, its credentials are deleted and a Google grant is revoked; its history stays (status disconnected) and it leaves GET /v1/mailboxes, freeing its plan slot. A purchased mailbox is cancelled instead: it stops warming up now and is deleted at the end of its paid month (status cancelling, cancelsAt). Idempotent.",
				"responses": {
					"200": {
						"description": "The mailbox",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/Mailbox"
										}
									},
									"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": "mailboxId",
						"required": true,
						"description": "The mailbox's id."
					},
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			}
		},
		"/v1/mailboxes/{mailboxId}/pause": {
			"post": {
				"operationId": "pauseMailbox",
				"tags": ["Mailboxes"],
				"summary": "Pause a mailbox",
				"description": "No warm-up and no outreach until resumed; what was planned is cancelled. Only an active mailbox can be paused (409 otherwise).",
				"responses": {
					"200": {
						"description": "The mailbox",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/Mailbox"
										}
									},
									"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": "mailboxId",
						"required": true,
						"description": "The mailbox's id."
					},
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			}
		},
		"/v1/mailboxes/{mailboxId}/resume": {
			"post": {
				"operationId": "resumeMailbox",
				"tags": ["Mailboxes"],
				"summary": "Resume a paused mailbox",
				"description": "402 when the plan has no room for it among the mailboxes that work (after a downgrade); 409 when it isn't paused.",
				"responses": {
					"200": {
						"description": "The mailbox",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/Mailbox"
										}
									},
									"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": "mailboxId",
						"required": true,
						"description": "The mailbox's id."
					},
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			}
		},
		"/v1/domains": {
			"get": {
				"operationId": "listDomains",
				"tags": ["Domains"],
				"summary": "List sending domains",
				"description": "Every domain the workspace's mailboxes send from, by name, with its latest health report (SPF, DKIM, DMARC, MX, blocklists, age, website, MTA-STS, TLS-RPT, BIMI), its blocklist status and its reputation. Domains are checked when a mailbox connects and every 6 hours.",
				"responses": {
					"200": {
						"description": "The domains",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "array",
											"items": {
												"$ref": "#/components/schemas/SendingDomain"
											}
										}
									},
									"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/domains/check": {
			"post": {
				"operationId": "analyzeDomain",
				"tags": ["Domains"],
				"summary": "Analyse any domain",
				"description": "Runs every health check on any domain — a prospect's, a competitor's, one you are about to buy — and returns the report; nothing is saved. Mail providers are inferred from its MX. A URL or an email address is reduced to its domain (422 when it isn't a valid domain). Spamhaus lists are queried only when this server has a Spamhaus Data Query Service key; the report says when they weren't. `info` checks are nice to have, never problems; `unknown` means a lookup couldn't complete (a list refusing the query is never read as \"not listed\"). At most 30 analyses a minute per workspace (429).",
				"responses": {
					"200": {
						"description": "The report",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/DomainHealthReport"
										}
									},
									"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/AnalyzeDomainInput"
							}
						}
					}
				},
				"parameters": [
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			}
		},
		"/v1/domains/search": {
			"get": {
				"operationId": "searchDomains",
				"tags": ["Domains"],
				"summary": "Search domains to buy",
				"description": "Look-alike outreach domains for a brand (getacme.com, tryacme.com, acmehq.com…) — or the exact domain typed — with their availability and Outvoy's yearly price, plus the monthly price per mailbox. Premium names are never offered.",
				"responses": {
					"200": {
						"description": "Available names and prices",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "object",
											"properties": {
												"exact": {
													"$ref": "#/components/schemas/DomainSuggestion"
												},
												"suggestions": {
													"type": "array",
													"items": {
														"$ref": "#/components/schemas/DomainSuggestion"
													}
												},
												"mailboxMonthlyPriceUsd": {
													"type": "number"
												}
											},
											"required": ["suggestions", "mailboxMonthlyPriceUsd"]
										}
									},
									"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": "q",
						"in": "query",
						"required": true,
						"description": "A brand (\"Acme\") or a full domain (\"getacme.com\"). Suggestions are built the way outreach domains are named.",
						"schema": {
							"type": "string",
							"minLength": 2,
							"maxLength": 100,
							"example": "acme"
						}
					}
				]
			}
		},
		"/v1/domains/{domainId}": {
			"get": {
				"operationId": "getDomain",
				"tags": ["Domains"],
				"summary": "Get a sending domain",
				"description": "The domain with its latest health report, its live mailboxes (with today's warm-up numbers) and its reputation over the last 30 days, oldest first.",
				"responses": {
					"200": {
						"description": "The domain",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"allOf": [
												{
													"$ref": "#/components/schemas/SendingDomain"
												},
												{
													"type": "object",
													"properties": {
														"mailboxList": {
															"type": "array",
															"items": {
																"$ref": "#/components/schemas/Mailbox"
															}
														},
														"history": {
															"type": "array",
															"items": {
																"$ref": "#/components/schemas/DomainReputationDay"
															},
															"description": "The domain's reputation over the last 30 days, oldest first."
														}
													},
													"required": ["mailboxList", "history"]
												}
											]
										}
									},
									"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": "domainId",
						"required": true,
						"description": "The domain's id."
					}
				]
			}
		},
		"/v1/domains/{domainId}/check": {
			"post": {
				"operationId": "checkDomain",
				"tags": ["Domains"],
				"summary": "Re-check a sending domain",
				"description": "Runs the domain's health checks now and saves the report in its history. A check that changes status emits domain.health_changed; a new blocklisting domain.blocklisted (the workspace owners are emailed); leaving a list domain.delisted. At most once a minute per domain (429).",
				"responses": {
					"200": {
						"description": "The domain and its new report",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "object",
											"properties": {
												"domain": {
													"$ref": "#/components/schemas/SendingDomain"
												},
												"report": {
													"$ref": "#/components/schemas/DomainHealthReport"
												}
											},
											"required": ["domain", "report"]
										}
									},
									"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": "domainId",
						"required": true,
						"description": "The domain's id."
					},
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			}
		},
		"/v1/domain-orders": {
			"post": {
				"operationId": "createDomainOrder",
				"tags": ["Domain orders"],
				"summary": "Buy domains and mailboxes (console session only)",
				"description": "Up to 5 domains (from `GET /v1/domains/search`), 1–5 mailboxes each (2–3 is the healthy number), on Google Workspace. Each domain's yearly price is paid once and every mailbox monthly (`$10`). With no mailbox subscription yet the answer carries a Stripe Checkout `checkoutUrl` and the order starts once Stripe confirms the payment; with one, the order is charged to the card on file now and starts at once. Every domain is checked again with the registrar: a taken, premium or unsold name is 422. Then Outvoy registers the domains, writes their DNS, creates the mailboxes, connects them and starts their warm-up — the order shows every step. Needs a plan (402); 403 with an API key (money moves only from the console); 402 when the card is declined; 503 when buying isn't configured on this server.",
				"responses": {
					"200": {
						"description": "The order, and where to pay when it needs a checkout",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "object",
											"properties": {
												"order": {
													"$ref": "#/components/schemas/DomainOrder"
												},
												"checkoutUrl": {
													"type": "string",
													"format": "uri",
													"description": "Stripe Checkout, when the workspace has no mailbox subscription yet. Otherwise the order was charged to the card on file and is already provisioning."
												}
											},
											"required": ["order"]
										}
									},
									"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/CreateDomainOrderInput"
							}
						}
					}
				},
				"parameters": [
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			},
			"get": {
				"operationId": "listDomainOrders",
				"tags": ["Domain orders"],
				"summary": "List domain orders",
				"description": "The workspace's orders of domains and mailboxes, newest first, each with every domain's steps (register, DNS, add to Google Workspace, create the mailboxes, DKIM, connect) and their state.",
				"responses": {
					"200": {
						"description": "The orders",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "array",
											"items": {
												"$ref": "#/components/schemas/DomainOrder"
											}
										}
									},
									"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/domain-orders/{orderId}": {
			"get": {
				"operationId": "getDomainOrder",
				"tags": ["Domain orders"],
				"summary": "Get a domain order",
				"description": "One order with every domain's steps as they happen: `status` (`awaiting_payment`, `provisioning`, `awaiting_operator` — the mailboxes warm up while Outvoy finishes DKIM —, `completed`, `failed`, `cancelled`), each step's attempts and what it is waiting for, and each mailbox's `mailboxId` once connected.",
				"responses": {
					"200": {
						"description": "The order",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/DomainOrder"
										}
									},
									"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": "orderId",
						"required": true,
						"description": "The order's id."
					}
				]
			}
		},
		"/v1/placement-tests": {
			"post": {
				"operationId": "runPlacementTest",
				"tags": ["Deliverability"],
				"summary": "Run an inbox placement test",
				"description": "Sends your exact subject and body (plain text) from the mailbox to Outvoy's seed mailboxes at Gmail, Google Workspace, Outlook.com, Microsoft 365, Yahoo and others — never to other customers' mailboxes — and reports where it landed at each, with the authentication verdicts their providers wrote. Results arrive within minutes; the test completes when every seed was found or after an hour. Real emails: at most 3 tests a day per mailbox (429). Sandbox mailboxes test against simulated seeds. 503 when this server has no seed mailboxes for real mailboxes.",
				"responses": {
					"200": {
						"description": "The test, running",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/PlacementTest"
										}
									},
									"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/RunPlacementTestInput"
							}
						}
					}
				},
				"parameters": [
					{
						"$ref": "#/components/parameters/IdempotencyKey"
					}
				]
			},
			"get": {
				"operationId": "listPlacementTests",
				"tags": ["Deliverability"],
				"summary": "List placement tests",
				"description": "Newest first; pass mailboxId for one mailbox's.",
				"responses": {
					"200": {
						"description": "A page of tests",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "array",
											"items": {
												"$ref": "#/components/schemas/PlacementTest"
											}
										},
										"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": "mailboxId",
						"in": "query",
						"required": false,
						"schema": {
							"type": "string"
						}
					},
					{
						"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/placement-tests/{testId}": {
			"get": {
				"operationId": "getPlacementTest",
				"tags": ["Deliverability"],
				"summary": "Get a placement test",
				"description": "Its status, score (the share of seeds where it reached the inbox), placement overall and per provider, and every seed's result.",
				"responses": {
					"200": {
						"description": "The test",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/PlacementTest"
										}
									},
									"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": "testId",
						"required": true,
						"description": "The test's id."
					}
				]
			}
		},
		"/v1/deliverability/overview": {
			"get": {
				"operationId": "getDeliverabilityOverview",
				"tags": ["Deliverability"],
				"summary": "Deliverability at a glance",
				"description": "The workspace's mailboxes by readiness, average reputation score, 7-day inbox placement overall and by receiving provider, the last 30 days of warm-up mail (where it landed), how many cold emails a day the mailboxes can carry now, the warm-up network's size, and what needs attention (mailboxes to reconnect or at risk, blocklisted domains, failing checks, orders waiting).",
				"responses": {
					"200": {
						"description": "The overview",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"$ref": "#/components/schemas/DeliverabilityOverview"
										}
									},
									"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/mailboxes/{mailboxId}/stats": {
			"get": {
				"operationId": "getMailboxStats",
				"tags": ["Deliverability"],
				"summary": "A mailbox's warm-up, day by day",
				"description": "Per local day of the mailbox (oldest first): warm-up emails it sent, where they landed (inbox, promotions/other tabs, spam, missing), how many the network rescued from spam, what it received and the replies it got, and the reputation score the day closed on.",
				"responses": {
					"200": {
						"description": "The days",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "array",
											"items": {
												"$ref": "#/components/schemas/MailboxDailyStat"
											}
										}
									},
									"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": "days",
						"in": "query",
						"required": false,
						"description": "How many local days back (1–90, default 30).",
						"schema": {
							"type": "integer",
							"minimum": 1,
							"maximum": 90,
							"default": 30
						}
					},
					{
						"schema": {
							"type": "string"
						},
						"in": "path",
						"name": "mailboxId",
						"required": true,
						"description": "The mailbox's id."
					}
				]
			}
		},
		"/v1/mailboxes/{mailboxId}/warmup-activity": {
			"get": {
				"operationId": "listWarmupActivity",
				"tags": ["Deliverability"],
				"summary": "A mailbox's warm-up activity",
				"description": "The warm-up emails it sent (with where each landed) and received, newest first. The other mailbox is shown only by its provider: who it is stays private to its workspace.",
				"responses": {
					"200": {
						"description": "A page of activity",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"data": {
											"type": "array",
											"items": {
												"$ref": "#/components/schemas/WarmupActivity"
											}
										},
										"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": "mailboxId",
						"required": true,
						"description": "The mailbox's id."
					}
				]
			}
		}
	},
	"components": {
		"schemas": {
			"SignInProvidersOutput": {
				"type": "object",
				"properties": {
					"data": {
						"type": "object",
						"properties": {
							"providers": {
								"type": "array",
								"items": {
									"type": "string",
									"enum": ["google", "github"]
								},
								"description": "The providers this deployment can sign in with. Empty when none is configured."
							}
						},
						"required": ["providers"]
					}
				},
				"required": ["data"]
			},
			"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
			},
			"StartProviderSignInOutput": {
				"type": "object",
				"properties": {
					"data": {
						"type": "object",
						"properties": {
							"url": {
								"type": "string",
								"format": "uri",
								"description": "The provider's consent page. It sends the browser back to the console's /auth/callback/<provider>."
							}
						},
						"required": ["url"]
					}
				},
				"required": ["data"]
			},
			"StartProviderSignInInput": {
				"type": "object",
				"properties": {
					"state": {
						"type": "string",
						"minLength": 16,
						"maxLength": 128,
						"pattern": "^[A-Za-z0-9_-]+$",
						"description": "Random value the caller keeps and checks when the provider sends the browser back."
					},
					"codeChallenge": {
						"type": "string",
						"minLength": 43,
						"maxLength": 128,
						"pattern": "^[A-Za-z0-9_-]+$",
						"description": "PKCE S256 challenge: base64url(SHA-256(codeVerifier)), without padding."
					}
				},
				"required": ["state", "codeChallenge"],
				"additionalProperties": false
			},
			"ProviderSessionOutput": {
				"type": "object",
				"properties": {
					"data": {
						"type": "object",
						"properties": {
							"token": {
								"type": "string"
							},
							"expiresAt": {
								"type": "string",
								"format": "date-time"
							},
							"user": {
								"$ref": "#/components/schemas/User"
							},
							"created": {
								"type": "boolean"
							}
						},
						"required": ["token", "expiresAt", "user", "created"]
					}
				},
				"required": ["data"]
			},
			"CompleteProviderSignInInput": {
				"type": "object",
				"properties": {
					"code": {
						"type": "string",
						"minLength": 1,
						"maxLength": 2048,
						"description": "The authorization code the provider sent back."
					},
					"codeVerifier": {
						"type": "string",
						"minLength": 43,
						"maxLength": 128,
						"pattern": "^[A-Za-z0-9_-]+$",
						"description": "The PKCE verifier behind the challenge sent to start."
					}
				},
				"required": ["code", "codeVerifier"],
				"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"
				]
			},
			"ConnectWithSessionInput": {
				"type": "object",
				"properties": {
					"accessToken": {
						"type": "string",
						"minLength": 1,
						"maxLength": 4096,
						"description": "LinkedIn's `li_at` session cookie, read by the extension when the person clicks. Handed to the LinkedIn provider to connect the account; Outvoy never stores it."
					},
					"userAgent": {
						"type": "string",
						"minLength": 1,
						"maxLength": 1024,
						"description": "The user agent of the browser the cookie comes from (LinkedIn ties the session to it)."
					}
				},
				"required": ["accessToken", "userAgent"],
				"additionalProperties": false
			},
			"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",
							"trial",
							"standard",
							"tier_1",
							"tier_2",
							"tier_3",
							"tier_4"
						]
					},
					"planName": {
						"type": "string",
						"example": "Outvoy"
					},
					"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",
						"description": "Absent when unlimited."
					},
					"liveCampaigns": {
						"type": "integer",
						"description": "Absent when unlimited."
					},
					"mailboxes": {
						"type": "integer",
						"description": "The workspace's own mailboxes connected at once (warm-up, reputation and placement tests). Mailboxes bought through Outvoy are paid one by one and don't count."
					},
					"sandboxMailboxes": {
						"type": "integer",
						"description": "Simulated mailboxes, to rehearse warm-up and placement tests."
					}
				},
				"required": [
					"linkedinSenders",
					"includedLinkedinSenders",
					"extraLinkedinSenders",
					"sandboxSenders",
					"mailboxes",
					"sandboxMailboxes"
				]
			},
			"WorkspaceBilling": {
				"type": "object",
				"properties": {
					"source": {
						"type": "string",
						"enum": ["subscription", "license", "comp", "none"],
						"description": "Where the plan comes from: a `subscription` (Stripe, priced per connected LinkedIn account), 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",
							"mailbox.connected",
							"mailbox.needs_reconnect",
							"mailbox.reputation_changed",
							"mailbox.ready",
							"domain.health_changed",
							"domain.blocklisted",
							"domain.delisted",
							"domain_order.completed",
							"domain_order.failed",
							"placement_test.completed"
						]
					},
					"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",
								"mailbox.connected",
								"mailbox.needs_reconnect",
								"mailbox.reputation_changed",
								"mailbox.ready",
								"domain.health_changed",
								"domain.blocklisted",
								"domain.delisted",
								"domain_order.completed",
								"domain_order.failed",
								"placement_test.completed"
							]
						},
						"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",
								"mailbox.connected",
								"mailbox.needs_reconnect",
								"mailbox.reputation_changed",
								"mailbox.ready",
								"domain.health_changed",
								"domain.blocklisted",
								"domain.delisted",
								"domain_order.completed",
								"domain_order.failed",
								"placement_test.completed"
							]
						},
						"maxItems": 36,
						"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",
								"mailbox.connected",
								"mailbox.needs_reconnect",
								"mailbox.reputation_changed",
								"mailbox.ready",
								"domain.health_changed",
								"domain.blocklisted",
								"domain.delisted",
								"domain_order.completed",
								"domain_order.failed",
								"placement_test.completed"
							]
						},
						"maxItems": 36,
						"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",
							"trial",
							"standard",
							"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",
							"trial",
							"standard",
							"tier_1",
							"tier_2",
							"tier_3",
							"tier_4"
						]
					},
					"planName": {
						"type": "string",
						"example": "Outvoy"
					},
					"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"
					},
					"trialDays": {
						"type": "integer",
						"exclusiveMinimum": 0,
						"description": "How many days the trial lasts: 7, or 14 once extended by the cancellation flow's offer. Only while trialing."
					},
					"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."
					},
					"interval": {
						"type": "string",
						"enum": ["month", "year"],
						"description": "How often the subscription is charged; only when `source` is `subscription`."
					},
					"billedAccounts": {
						"type": "integer",
						"description": "LinkedIn accounts the subscription bills now (at least 1: the first is the minimum). Connecting one adds it at once; disconnecting one takes it off at the next renewal."
					},
					"connectedAccounts": {
						"type": "integer",
						"description": "LinkedIn accounts connected now (paused ones included; disconnected ones don't count)."
					},
					"nextChargeUsd": {
						"type": "number",
						"description": "What the next charge will be for the accounts connected now, before tax and any discount; only when `source` is `subscription`."
					},
					"discount": {
						"type": "object",
						"properties": {
							"percentOff": {
								"type": "number"
							},
							"endsAt": {
								"type": "string",
								"format": "date-time"
							}
						},
						"required": ["percentOff"],
						"description": "A discount on the subscription now (the cancellation flow's offer, once accepted), and when it ends."
					},
					"retentionOffer": {
						"type": "string",
						"enum": ["extend_trial", "discount"],
						"description": "What the cancellation flow can still offer before the subscription ends: 7 more days of trial (once), or, on a monthly plan, a discount on the next months (once). Absent when there is nothing left to offer."
					},
					"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"
					},
					"mailboxes": {
						"$ref": "#/components/schemas/MailboxBilling"
					}
				},
				"required": [
					"plan",
					"planName",
					"source",
					"cancelAtPeriodEnd",
					"connectedAccounts",
					"trialEligible",
					"checkoutAvailable",
					"simulated",
					"extraSenders",
					"mailboxes"
				]
			},
			"ExtraSendersBilling": {
				"type": "object",
				"properties": {
					"offered": {
						"type": "boolean",
						"description": "Whether this workspace can buy extra LinkedIn accounts: AppSumo lifetime licences only (the subscription grows with every account connected)."
					},
					"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"
				]
			},
			"MailboxBilling": {
				"type": "object",
				"properties": {
					"quantity": {
						"type": "integer",
						"description": "Purchased mailboxes the workspace pays for each month (0 before the first domain order)."
					},
					"priceUsdPerMonth": {
						"type": "number",
						"description": "What one purchased mailbox costs a month."
					},
					"status": {
						"type": "string",
						"enum": [
							"trialing",
							"active",
							"past_due",
							"canceled",
							"incomplete"
						],
						"description": "The mailbox subscription's status, once there is one."
					},
					"renewsAt": {
						"type": "string",
						"format": "date-time",
						"description": "The next monthly charge for the mailboxes."
					}
				},
				"required": ["quantity", "priceUsdPerMonth"]
			},
			"StartCheckoutInput": {
				"type": "object",
				"properties": {
					"interval": {
						"type": "string",
						"enum": ["month", "year"],
						"default": "month",
						"description": "Pay monthly, or yearly (12 months for the price of 10). The price is per connected LinkedIn account: the first $39/month, then less for each one. A first subscription starts with a 7-day free trial; the card is charged on day 8 unless it is cancelled."
					}
				},
				"additionalProperties": false
			},
			"CancelSubscriptionInput": {
				"type": "object",
				"properties": {
					"reason": {
						"type": "string",
						"enum": [
							"too_expensive",
							"missing_features",
							"switched_service",
							"unused",
							"too_complex",
							"low_quality",
							"customer_service",
							"other"
						],
						"description": "Why the subscription is cancelled, if the customer says."
					},
					"comment": {
						"type": "string",
						"maxLength": 500
					}
				},
				"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"
					},
					{
						"$ref": "#/components/schemas/ConditionStep"
					},
					{
						"$ref": "#/components/schemas/SplitStep"
					},
					{
						"$ref": "#/components/schemas/WaitStep"
					},
					{
						"$ref": "#/components/schemas/EndStep"
					}
				],
				"discriminator": {
					"propertyName": "type",
					"mapping": {
						"visit_profile": "#/components/schemas/VisitProfileStep",
						"like_post": "#/components/schemas/LikePostStep",
						"invite": "#/components/schemas/InviteStep",
						"message": "#/components/schemas/MessageStep",
						"condition": "#/components/schemas/ConditionStep",
						"split": "#/components/schemas/SplitStep",
						"wait": "#/components/schemas/WaitStep",
						"end": "#/components/schemas/EndStep"
					}
				},
				"description": "One step of a campaign. Steps run in list order unless one says where to go (next, onAccepted / onNotAccepted, onTrue / onFalse, variants[].next): jumps only go forward, to a later step's id or to \"end\", so a campaign can branch and paths can meet again, but nothing repeats."
			},
			"VisitProfileStep": {
				"type": "object",
				"properties": {
					"type": {
						"type": "string",
						"enum": ["visit_profile"]
					},
					"id": {
						"type": "string",
						"pattern": "^[A-Za-z][A-Za-z0-9_-]{0,39}$",
						"description": "The step's name (a letter, then letters, digits, - or _; at most 40), unique in the campaign, so other steps can go to it. Only needed on steps something jumps to.",
						"example": "follow_up"
					},
					"next": {
						"type": "string",
						"pattern": "^[A-Za-z][A-Za-z0-9_-]{0,39}$",
						"description": "Where the lead goes next: the id of a LATER step (jumps only go forward, so no loop is possible), or \"end\" to finish the lead here. Omitted: the step right after this one in the list (or the end, after the last step).",
						"example": "follow_up"
					},
					"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"]
					},
					"id": {
						"type": "string",
						"pattern": "^[A-Za-z][A-Za-z0-9_-]{0,39}$",
						"description": "The step's name (a letter, then letters, digits, - or _; at most 40), unique in the campaign, so other steps can go to it. Only needed on steps something jumps to.",
						"example": "follow_up"
					},
					"next": {
						"type": "string",
						"pattern": "^[A-Za-z][A-Za-z0-9_-]{0,39}$",
						"description": "Where the lead goes next: the id of a LATER step (jumps only go forward, so no loop is possible), or \"end\" to finish the lead here. Omitted: the step right after this one in the list (or the end, after the last step).",
						"example": "follow_up"
					},
					"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"]
					},
					"id": {
						"type": "string",
						"pattern": "^[A-Za-z][A-Za-z0-9_-]{0,39}$",
						"description": "The step's name (a letter, then letters, digits, - or _; at most 40), unique in the campaign, so other steps can go to it. Only needed on steps something jumps to.",
						"example": "follow_up"
					},
					"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}}"
					},
					"acceptWithinDays": {
						"type": "integer",
						"minimum": 1,
						"maximum": 30,
						"description": "Days to wait for this invitation to be accepted before withdrawing it (1–30). Default: settings.acceptanceWindowDays."
					},
					"onAccepted": {
						"type": "string",
						"pattern": "^[A-Za-z][A-Za-z0-9_-]{0,39}$",
						"description": "Where they go once connected — they accepted, or were connected already (ifAlreadyConnected = continue). Omitted: the next step. The delay of that step counts from the acceptance.",
						"example": "follow_up"
					},
					"onNotAccepted": {
						"type": "string",
						"pattern": "^[A-Za-z][A-Za-z0-9_-]{0,39}$",
						"description": "Where they go when the acceptance window ends without an acceptance (the invitation is withdrawn first). Omitted: \"end\", the lead completes with stopReason not_accepted. Steps on this path never reach them as a connection: no message step.",
						"example": "follow_up"
					}
				},
				"required": ["type"],
				"additionalProperties": false,
				"description": "Send a connection invitation, then wait for the acceptance. At most one on any path through the campaign. Skipped when they are already connected (they go to onAccepted); treated as sent when an invitation is already pending."
			},
			"MessageStep": {
				"type": "object",
				"properties": {
					"type": {
						"type": "string",
						"enum": ["message"]
					},
					"id": {
						"type": "string",
						"pattern": "^[A-Za-z][A-Za-z0-9_-]{0,39}$",
						"description": "The step's name (a letter, then letters, digits, - or _; at most 40), unique in the campaign, so other steps can go to it. Only needed on steps something jumps to.",
						"example": "follow_up"
					},
					"next": {
						"type": "string",
						"pattern": "^[A-Za-z][A-Za-z0-9_-]{0,39}$",
						"description": "Where the lead goes next: the id of a LATER step (jumps only go forward, so no loop is possible), or \"end\" to finish the lead here. Omitted: the step right after this one in the list (or the end, after the last step).",
						"example": "follow_up"
					},
					"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. Every path to it must make them a connection first: an invite's onAccepted, a `connected` condition's onTrue, or settings.audience = connected_only."
			},
			"ConditionStep": {
				"type": "object",
				"properties": {
					"type": {
						"type": "string",
						"enum": ["condition"]
					},
					"id": {
						"type": "string",
						"pattern": "^[A-Za-z][A-Za-z0-9_-]{0,39}$",
						"description": "The step's name (a letter, then letters, digits, - or _; at most 40), unique in the campaign, so other steps can go to it. Only needed on steps something jumps to.",
						"example": "follow_up"
					},
					"delay": {
						"allOf": [
							{
								"$ref": "#/components/schemas/StepDelay"
							},
							{
								"description": "How long to wait before checking (the check happens then, with what is known at that moment)."
							}
						]
					},
					"if": {
						"$ref": "#/components/schemas/CampaignCondition"
					},
					"onTrue": {
						"type": "string",
						"pattern": "^[A-Za-z][A-Za-z0-9_-]{0,39}$",
						"description": "Where they go when the condition holds. Omitted: the next step.",
						"example": "follow_up"
					},
					"onFalse": {
						"type": "string",
						"pattern": "^[A-Za-z][A-Za-z0-9_-]{0,39}$",
						"description": "Where they go when it doesn't. Omitted: the next step. onTrue and onFalse can't both lead to the same place.",
						"example": "follow_up"
					}
				},
				"required": ["type", "if"],
				"additionalProperties": false,
				"description": "Sends nothing: checks the lead and sends them one way or the other."
			},
			"CampaignCondition": {
				"anyOf": [
					{
						"type": "object",
						"properties": {
							"fact": {
								"type": "string",
								"enum": [
									"connected",
									"invite_accepted",
									"already_connected",
									"invited",
									"messaged"
								],
								"description": "connected: a 1st-degree connection of their sender now. invite_accepted: they accepted an invitation of this campaign. already_connected: connected before this campaign invited them. invited: this campaign invited them. messaged: this campaign sent them a LinkedIn message."
							}
						},
						"required": ["fact"],
						"additionalProperties": false
					},
					{
						"type": "object",
						"properties": {
							"variable": {
								"type": "string",
								"minLength": 1,
								"maxLength": 60,
								"description": "A template variable: firstName, lastName, fullName, company, title, headline, location, or fields.<key> (the lead's or the enrollment's own fields). Read exactly as {{variable}} would render it.",
								"example": "fields.industry"
							},
							"operator": {
								"type": "string",
								"enum": [
									"exists",
									"not_exists",
									"equals",
									"not_equals",
									"contains",
									"not_contains",
									"starts_with",
									"ends_with",
									"in",
									"not_in"
								],
								"description": "exists / not_exists (has a value or not), equals / not_equals, contains / not_contains, starts_with / ends_with (text, case and accents ignored), in / not_in (one of a list). Comparing a variable with no value: only not_exists, not_equals, not_contains and not_in hold."
							},
							"value": {
								"anyOf": [
									{
										"type": "string",
										"maxLength": 200
									},
									{
										"type": "array",
										"items": {
											"type": "string",
											"maxLength": 200
										},
										"minItems": 1,
										"maxItems": 30
									}
								],
								"description": "What to compare with: text, or a list for in / not_in. Not used by exists / not_exists."
							}
						},
						"required": ["variable", "operator"],
						"additionalProperties": false
					},
					{
						"type": "object",
						"properties": {
							"all": {
								"type": "array",
								"items": {
									"$ref": "#/components/schemas/CampaignCondition"
								},
								"minItems": 1,
								"maxItems": 10
							}
						},
						"required": ["all"],
						"additionalProperties": false
					},
					{
						"type": "object",
						"properties": {
							"any": {
								"type": "array",
								"items": {
									"$ref": "#/components/schemas/CampaignCondition"
								},
								"minItems": 1,
								"maxItems": 10
							}
						},
						"required": ["any"],
						"additionalProperties": false
					},
					{
						"type": "object",
						"properties": {
							"not": {
								"$ref": "#/components/schemas/CampaignCondition"
							}
						},
						"required": ["not"],
						"additionalProperties": false
					}
				],
				"description": "A check on the lead: a fact ({ \"fact\": \"connected\" }), a variable ({ \"variable\": \"title\", \"operator\": \"contains\", \"value\": \"CEO\" }), or several combined ({ \"all\": [...] }, { \"any\": [...] }, { \"not\": ... })."
			},
			"SplitStep": {
				"type": "object",
				"properties": {
					"type": {
						"type": "string",
						"enum": ["split"]
					},
					"id": {
						"type": "string",
						"pattern": "^[A-Za-z][A-Za-z0-9_-]{0,39}$",
						"description": "The step's name (a letter, then letters, digits, - or _; at most 40), unique in the campaign, so other steps can go to it. Only needed on steps something jumps to.",
						"example": "follow_up"
					},
					"delay": {
						"$ref": "#/components/schemas/StepDelay"
					},
					"variants": {
						"type": "array",
						"items": {
							"type": "object",
							"properties": {
								"weight": {
									"type": "integer",
									"minimum": 1,
									"maximum": 99,
									"description": "Share of the leads, in percent. The weights add up to 100."
								},
								"next": {
									"type": "string",
									"pattern": "^[A-Za-z][A-Za-z0-9_-]{0,39}$",
									"description": "Where the lead goes next: the id of a LATER step (jumps only go forward, so no loop is possible), or \"end\" to finish the lead here. Omitted: the step right after this one in the list (or the end, after the last step).",
									"example": "follow_up"
								}
							},
							"required": ["weight"],
							"additionalProperties": false
						},
						"minItems": 2,
						"maxItems": 5
					}
				},
				"required": ["type", "variants"],
				"additionalProperties": false,
				"description": "Sends nothing: spreads leads across 2–5 variants by percentage, for A/B tests. Each lead always lands in the same variant."
			},
			"WaitStep": {
				"type": "object",
				"properties": {
					"type": {
						"type": "string",
						"enum": ["wait"]
					},
					"id": {
						"type": "string",
						"pattern": "^[A-Za-z][A-Za-z0-9_-]{0,39}$",
						"description": "The step's name (a letter, then letters, digits, - or _; at most 40), unique in the campaign, so other steps can go to it. Only needed on steps something jumps to.",
						"example": "follow_up"
					},
					"next": {
						"type": "string",
						"pattern": "^[A-Za-z][A-Za-z0-9_-]{0,39}$",
						"description": "Where the lead goes next: the id of a LATER step (jumps only go forward, so no loop is possible), or \"end\" to finish the lead here. Omitted: the step right after this one in the list (or the end, after the last step).",
						"example": "follow_up"
					},
					"delay": {
						"allOf": [
							{
								"$ref": "#/components/schemas/StepDelay"
							},
							{
								"description": "How long to wait. Must be longer than 0."
							}
						]
					}
				},
				"required": ["type", "delay"],
				"additionalProperties": false,
				"description": "Sends nothing: only waits."
			},
			"EndStep": {
				"type": "object",
				"properties": {
					"type": {
						"type": "string",
						"enum": ["end"]
					},
					"id": {
						"type": "string",
						"pattern": "^[A-Za-z][A-Za-z0-9_-]{0,39}$",
						"description": "The step's name (a letter, then letters, digits, - or _; at most 40), unique in the campaign, so other steps can go to it. Only needed on steps something jumps to.",
						"example": "follow_up"
					},
					"delay": {
						"$ref": "#/components/schemas/StepDelay"
					},
					"outcome": {
						"type": "string",
						"minLength": 1,
						"maxLength": 60,
						"description": "A name for how this path ends (\"no reply\", \"not a fit\"…): stored on the enrollment and counted in the stats.",
						"example": "not a fit"
					}
				},
				"required": ["type"],
				"additionalProperties": false,
				"description": "Finishes the lead's path here. The lead completes."
			},
			"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": 50,
						"default": [],
						"description": "The workflow, at most 50 steps. Actions: visit_profile, like_post, invite (optional note ≤ 300 rendered characters; then waits for the acceptance and goes to onAccepted or, when the window closes, onNotAccepted), message (≤ 8000 rendered characters, only to 1st-degree connections). Logic, which sends nothing: condition (if, onTrue, onFalse: on facts like connected or on the lead's variables), split (A/B variants by percentage), wait, end (with an optional outcome). Steps run in list order unless one names where to go — a later step's id or \"end\" — so a workflow can branch and paths can meet again, but nothing repeats. Every path: at most one invite, at most 12 invitations and messages, at most 120 days; every message must be reached only once connected. Each step has a delay from the previous step's completion (from the acceptance after an invite). 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": 50,
						"description": "Only while draft or paused. Live enrollments continue from the same step — the one with the same id when it has one, else the one at the same position — and their next planned step is planned again from the new steps."
					},
					"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"
						},
						"description": "The steps this lead can reach, in list order, rendered for them. Conditions on variables are judged with their values now, so a branch they rule out is left out (and can't block them); facts like connected are only known as the campaign runs, so both ways of those stay in."
					},
					"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",
							"condition",
							"split",
							"wait",
							"end"
						]
					},
					"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",
							"condition",
							"split",
							"wait",
							"end"
						]
					},
					"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)."
					},
					"outcome": {
						"type": "string",
						"description": "Completed at an end step that names an outcome: that name (\"not a fit\", \"no reply\"…).",
						"example": "not a fit"
					},
					"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",
							"advance"
						]
					},
					"status": {
						"type": "string",
						"enum": [
							"pending",
							"running",
							"done",
							"failed",
							"skipped",
							"cancelled"
						]
					},
					"stepIndex": {
						"type": "integer",
						"description": "The step it performs or evaluates (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."
					},
					"route": {
						"type": "string",
						"description": "advance actions (a condition, split, wait or end step evaluated): the way out the lead took — next, true, false, variant:<n> (0-based) or end. errorDetail says it in words.",
						"example": "true"
					}
				},
				"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
			},
			"Mailbox": {
				"type": "object",
				"properties": {
					"id": {
						"type": "string",
						"example": "mbx_4kQ8wT1zLm0PqRsT7uVwX"
					},
					"email": {
						"type": "string",
						"example": "jamie@getacme.com"
					},
					"displayName": {
						"type": "string",
						"example": "Jamie Rivera"
					},
					"provider": {
						"type": "string",
						"enum": ["google", "microsoft", "imap", "sandbox"]
					},
					"origin": {
						"type": "string",
						"enum": ["connected", "purchased", "sandbox"]
					},
					"status": {
						"type": "string",
						"enum": [
							"provisioning",
							"active",
							"paused",
							"needs_reconnect",
							"cancelling",
							"disconnected"
						]
					},
					"statusDetail": {
						"type": "string",
						"description": "Why the mailbox is in its status, in plain English."
					},
					"network": {
						"type": "string",
						"enum": ["live", "sandbox"],
						"description": "The warm-up network it belongs to: live (real mailboxes) or sandbox (simulated)."
					},
					"domainId": {
						"type": "string"
					},
					"domain": {
						"type": "string",
						"example": "getacme.com"
					},
					"schedule": {
						"$ref": "#/components/schemas/SenderSchedule"
					},
					"warmup": {
						"$ref": "#/components/schemas/MailboxWarmup"
					},
					"outreachDailyLimit": {
						"type": "integer",
						"minimum": 0,
						"description": "The customer's own cap on cold emails a day; absent = Outvoy's recommendation (reputation.recommendedDailyVolume). Campaigns use the lower of the two."
					},
					"reputation": {
						"$ref": "#/components/schemas/Reputation"
					},
					"today": {
						"$ref": "#/components/schemas/MailboxToday"
					},
					"connectedAt": {
						"type": "string",
						"format": "date-time"
					},
					"cancelsAt": {
						"type": "string",
						"format": "date-time",
						"description": "A purchased mailbox being cancelled: when it is deleted at the provider (the end of its paid month)."
					},
					"createdAt": {
						"type": "string",
						"format": "date-time"
					},
					"updatedAt": {
						"type": "string",
						"format": "date-time"
					}
				},
				"required": [
					"id",
					"email",
					"displayName",
					"provider",
					"origin",
					"status",
					"network",
					"domainId",
					"domain",
					"schedule",
					"warmup",
					"reputation",
					"today",
					"createdAt",
					"updatedAt"
				]
			},
			"MailboxWarmup": {
				"type": "object",
				"properties": {
					"enabled": {
						"type": "boolean"
					},
					"startVolume": {
						"type": "integer",
						"minimum": 1,
						"maximum": 20
					},
					"rampPerDay": {
						"type": "integer",
						"minimum": 0,
						"maximum": 10
					},
					"dailyMax": {
						"type": "integer",
						"minimum": 1,
						"maximum": 50
					},
					"replyRate": {
						"type": "integer",
						"minimum": 0,
						"maximum": 80
					},
					"weekdaysOnly": {
						"type": "boolean"
					},
					"startedAt": {
						"type": "string",
						"format": "date-time",
						"example": "2026-11-02T09:00:00.000Z"
					}
				},
				"required": [
					"enabled",
					"startVolume",
					"rampPerDay",
					"dailyMax",
					"replyRate",
					"weekdaysOnly",
					"startedAt"
				],
				"additionalProperties": false,
				"description": "Warm-up starts startVolume new conversations on day 1 and adds rampPerDay each day up to dailyMax, plus replies to what the mailbox receives; replyRate % of its own emails get an answer."
			},
			"Reputation": {
				"type": "object",
				"properties": {
					"score": {
						"type": "integer",
						"minimum": 0,
						"maximum": 100,
						"description": "0–100; absent while there isn't enough evidence (level unknown)."
					},
					"level": {
						"type": "string",
						"enum": ["excellent", "good", "fair", "poor", "critical", "unknown"]
					},
					"readiness": {
						"type": "string",
						"enum": [
							"warming",
							"ready",
							"limited",
							"at_risk",
							"not_warming",
							"inactive"
						]
					},
					"recommendedDailyVolume": {
						"type": "integer",
						"minimum": 0,
						"description": "Cold emails a day Outvoy recommends from this mailbox now (0 while warming, at risk or inactive)."
					},
					"summary": {
						"type": "string",
						"description": "The verdict in one sentence.",
						"example": "Ready: 96% inbox placement over 7 days, authentication passing."
					},
					"placement7d": {
						"$ref": "#/components/schemas/PlacementRates"
					},
					"byProvider": {
						"type": "array",
						"items": {
							"type": "object",
							"properties": {
								"provider": {
									"type": "string",
									"enum": ["google", "microsoft", "yahoo", "other"]
								},
								"rates": {
									"$ref": "#/components/schemas/PlacementRates"
								}
							},
							"required": ["provider", "rates"]
						},
						"description": "The 7-day placement per receiving provider."
					},
					"factors": {
						"type": "array",
						"items": {
							"$ref": "#/components/schemas/ReputationFactor"
						}
					},
					"warmupDay": {
						"type": "integer",
						"minimum": 0
					},
					"computedAt": {
						"type": "string",
						"format": "date-time"
					}
				},
				"required": [
					"level",
					"readiness",
					"recommendedDailyVolume",
					"summary",
					"placement7d",
					"byProvider",
					"factors",
					"computedAt"
				]
			},
			"PlacementRates": {
				"type": "object",
				"properties": {
					"checked": {
						"type": "integer",
						"description": "Messages looked up in their recipient's mailbox."
					},
					"inbox": {
						"type": "integer"
					},
					"promotions": {
						"type": "integer"
					},
					"spam": {
						"type": "integer"
					},
					"missing": {
						"type": "integer"
					},
					"inboxRate": {
						"type": "number",
						"minimum": 0,
						"maximum": 1,
						"description": "inbox ÷ checked; absent when nothing was checked. Promotions/Other tabs don't count as inbox."
					}
				},
				"required": ["checked", "inbox", "promotions", "spam", "missing"]
			},
			"ReputationFactor": {
				"type": "object",
				"properties": {
					"id": {
						"type": "string",
						"enum": ["placement", "authentication", "maturity", "trend", "cap"]
					},
					"label": {
						"type": "string",
						"example": "Inbox placement"
					},
					"points": {
						"type": "number",
						"description": "Points this factor earned (for a cap: the score's ceiling)."
					},
					"maxPoints": {
						"type": "number"
					},
					"detail": {
						"type": "string",
						"example": "Inbox placement 87% over 7 days (312 checked)"
					},
					"tone": {
						"type": "string",
						"enum": ["positive", "neutral", "negative"]
					}
				},
				"required": ["id", "label", "points", "maxPoints", "detail", "tone"]
			},
			"MailboxToday": {
				"type": "object",
				"properties": {
					"target": {
						"type": "integer",
						"description": "New warm-up conversations planned for today (the ramp, weekends and recovery applied)."
					},
					"sent": {
						"type": "integer",
						"description": "Warm-up emails sent today, replies included."
					},
					"conversationsStarted": {
						"type": "integer",
						"description": "Of them, new conversations (what `target` counts): replies come on top."
					},
					"received": {
						"type": "integer"
					},
					"repliesSent": {
						"type": "integer"
					}
				},
				"required": [
					"target",
					"sent",
					"conversationsStarted",
					"received",
					"repliesSent"
				]
			},
			"StartMailboxOauthInput": {
				"type": "object",
				"properties": {
					"provider": {
						"type": "string",
						"enum": ["google", "microsoft"],
						"description": "google: Gmail or Google Workspace; microsoft: Outlook.com or Microsoft 365."
					},
					"timezone": {
						"type": "string",
						"description": "The mailbox's timezone: warm-up runs in its working hours (default Europe/Madrid).",
						"example": "Europe/Madrid"
					},
					"reconnectMailboxId": {
						"type": "string",
						"description": "Give a mailbox in needs_reconnect its access back instead of adding a new one."
					}
				},
				"required": ["provider"],
				"additionalProperties": false
			},
			"ConnectImapMailboxInput": {
				"type": "object",
				"properties": {
					"email": {
						"type": "string",
						"minLength": 3,
						"maxLength": 320,
						"example": "jamie@acme.io"
					},
					"displayName": {
						"type": "string",
						"minLength": 1,
						"maxLength": 200,
						"description": "The \"From\" name (default: the address)."
					},
					"imap": {
						"type": "object",
						"properties": {
							"host": {
								"type": "string",
								"minLength": 1,
								"maxLength": 253,
								"example": "imap.fastmail.com"
							},
							"port": {
								"type": "integer",
								"minimum": 1,
								"maximum": 65535,
								"example": 993
							},
							"security": {
								"type": "string",
								"enum": ["tls", "starttls"],
								"description": "tls: implicit TLS (993, 465); starttls: upgraded (143, 587)."
							},
							"username": {
								"type": "string",
								"minLength": 1,
								"maxLength": 320
							},
							"password": {
								"type": "string",
								"minLength": 1,
								"maxLength": 1024,
								"description": "Usually an app password. Sealed before it is stored; never returned or logged."
							}
						},
						"required": ["host", "port", "security", "username", "password"],
						"additionalProperties": false
					},
					"smtp": {
						"type": "object",
						"properties": {
							"host": {
								"type": "string",
								"minLength": 1,
								"maxLength": 253,
								"example": "imap.fastmail.com"
							},
							"port": {
								"type": "integer",
								"minimum": 1,
								"maximum": 65535,
								"example": 993
							},
							"security": {
								"type": "string",
								"enum": ["tls", "starttls"],
								"description": "tls: implicit TLS (993, 465); starttls: upgraded (143, 587)."
							},
							"username": {
								"type": "string",
								"minLength": 1,
								"maxLength": 320
							},
							"password": {
								"type": "string",
								"minLength": 1,
								"maxLength": 1024,
								"description": "Usually an app password. Sealed before it is stored; never returned or logged."
							}
						},
						"required": ["host", "port", "security", "username", "password"],
						"additionalProperties": false
					},
					"timezone": {
						"type": "string",
						"description": "The mailbox's timezone: warm-up runs in its working hours (default Europe/Madrid).",
						"example": "Europe/Madrid"
					},
					"reconnectMailboxId": {
						"type": "string"
					}
				},
				"required": ["email", "imap", "smtp"],
				"additionalProperties": false
			},
			"CreateSandboxMailboxInput": {
				"type": "object",
				"properties": {
					"displayName": {
						"type": "string",
						"minLength": 1,
						"maxLength": 200,
						"description": "Defaults to a generated persona's name."
					},
					"simulatedProvider": {
						"type": "string",
						"enum": ["google", "microsoft", "other"],
						"description": "Which provider it pretends to be hosted at (default google): placement differs by provider."
					},
					"timezone": {
						"type": "string",
						"description": "The mailbox's timezone: warm-up runs in its working hours (default Europe/Madrid).",
						"example": "Europe/Madrid"
					}
				},
				"additionalProperties": false
			},
			"UpdateMailboxInput": {
				"type": "object",
				"properties": {
					"displayName": {
						"type": "string",
						"minLength": 1,
						"maxLength": 200
					},
					"warmup": {
						"$ref": "#/components/schemas/MailboxWarmupUpdate"
					},
					"schedule": {
						"$ref": "#/components/schemas/SenderSchedule"
					},
					"outreachDailyLimit": {
						"type": ["integer", "null"],
						"minimum": 0,
						"maximum": 200,
						"description": "Your own cap on cold emails a day from this mailbox; null goes back to Outvoy's recommendation. Campaigns use the lower of the two."
					}
				},
				"additionalProperties": false
			},
			"MailboxWarmupUpdate": {
				"type": "object",
				"properties": {
					"enabled": {
						"type": "boolean"
					},
					"startVolume": {
						"type": "integer",
						"minimum": 1,
						"maximum": 20
					},
					"rampPerDay": {
						"type": "integer",
						"minimum": 0,
						"maximum": 10
					},
					"dailyMax": {
						"type": "integer",
						"minimum": 1,
						"maximum": 50
					},
					"replyRate": {
						"type": "integer",
						"minimum": 0,
						"maximum": 80
					},
					"weekdaysOnly": {
						"type": "boolean"
					}
				},
				"additionalProperties": false,
				"description": "Any subset of the warm-up settings: enabled, startVolume (1–20), rampPerDay (0–10), dailyMax (1–50), replyRate (0–80 %), weekdaysOnly."
			},
			"SendingDomain": {
				"type": "object",
				"properties": {
					"id": {
						"type": "string",
						"example": "dom_7Hj2kLm0PqRsT4uVwXyZb"
					},
					"name": {
						"type": "string",
						"example": "getacme.com"
					},
					"origin": {
						"type": "string",
						"enum": ["connected", "purchased", "sandbox"]
					},
					"mailboxes": {
						"type": "integer",
						"description": "Live mailboxes on this domain."
					},
					"health": {
						"$ref": "#/components/schemas/DomainHealthReport"
					},
					"reputation": {
						"type": "object",
						"properties": {
							"score": {
								"type": "integer"
							},
							"level": {
								"type": "string",
								"enum": [
									"excellent",
									"good",
									"fair",
									"poor",
									"critical",
									"unknown"
								]
							},
							"placement7d": {
								"$ref": "#/components/schemas/PlacementRates"
							}
						},
						"required": ["level", "placement7d"]
					},
					"registration": {
						"type": "object",
						"properties": {
							"registeredAt": {
								"type": "string",
								"format": "date-time"
							},
							"expiresAt": {
								"type": "string",
								"format": "date-time"
							},
							"autoRenew": {
								"type": "boolean"
							},
							"redirectUrl": {
								"type": "string",
								"format": "uri",
								"description": "Where the domain's website redirects (the customer's real site)."
							},
							"yearlyPriceUsd": {
								"type": "number"
							}
						},
						"required": [
							"registeredAt",
							"expiresAt",
							"autoRenew",
							"yearlyPriceUsd"
						],
						"description": "A domain bought through Outvoy: its registration."
					},
					"createdAt": {
						"type": "string",
						"format": "date-time"
					},
					"updatedAt": {
						"type": "string",
						"format": "date-time"
					}
				},
				"required": [
					"id",
					"name",
					"origin",
					"mailboxes",
					"reputation",
					"createdAt",
					"updatedAt"
				]
			},
			"DomainHealthReport": {
				"type": "object",
				"properties": {
					"domain": {
						"type": "string",
						"example": "getacme.com"
					},
					"checkedAt": {
						"type": "string",
						"format": "date-time"
					},
					"trigger": {
						"type": "string",
						"enum": ["connected", "manual", "scheduled", "order"]
					},
					"setupScore": {
						"type": "integer",
						"minimum": 0,
						"maximum": 100,
						"description": "Weighted share of the checks that pass (warnings count half; info and unknown checks don't count)."
					},
					"counts": {
						"type": "object",
						"properties": {
							"pass": {
								"type": "integer"
							},
							"warn": {
								"type": "integer"
							},
							"fail": {
								"type": "integer"
							},
							"info": {
								"type": "integer"
							},
							"unknown": {
								"type": "integer"
							}
						},
						"required": ["pass", "warn", "fail", "info", "unknown"]
					},
					"blocklisted": {
						"type": "boolean",
						"description": "Listed on at least one major blocklist."
					},
					"checks": {
						"type": "array",
						"items": {
							"$ref": "#/components/schemas/DomainCheck"
						}
					}
				},
				"required": [
					"domain",
					"checkedAt",
					"trigger",
					"setupScore",
					"counts",
					"blocklisted",
					"checks"
				],
				"description": "The latest health report; absent until the first one ran."
			},
			"DomainCheck": {
				"type": "object",
				"properties": {
					"id": {
						"type": "string",
						"enum": [
							"mx",
							"spf",
							"dkim",
							"dmarc",
							"blocklists",
							"domain_age",
							"website",
							"mta_sts",
							"tls_rpt",
							"bimi",
							"reverse_dns"
						]
					},
					"category": {
						"type": "string",
						"enum": [
							"authentication",
							"routing",
							"reputation",
							"infrastructure",
							"security"
						]
					},
					"status": {
						"type": "string",
						"enum": ["pass", "warn", "fail", "info", "unknown"]
					},
					"title": {
						"type": "string",
						"example": "DMARC"
					},
					"summary": {
						"type": "string",
						"description": "What was found, in one sentence.",
						"example": "DMARC is set to p=none: providers only report, they don't act."
					},
					"found": {
						"type": "array",
						"items": {
							"type": "string"
						}
					},
					"fix": {
						"type": "object",
						"properties": {
							"description": {
								"type": "string"
							},
							"records": {
								"type": "array",
								"items": {
									"$ref": "#/components/schemas/DnsRecord"
								}
							}
						},
						"required": ["description", "records"],
						"description": "How to fix it: one sentence and, when it is a DNS change, the exact records to add or replace."
					}
				},
				"required": ["id", "category", "status", "title", "summary", "found"]
			},
			"DnsRecord": {
				"type": "object",
				"properties": {
					"type": {
						"type": "string",
						"enum": ["A", "AAAA", "CNAME", "MX", "TXT", "NS"]
					},
					"host": {
						"type": "string"
					},
					"value": {
						"type": "string"
					},
					"priority": {
						"type": "integer",
						"minimum": 0,
						"maximum": 65535
					},
					"ttl": {
						"type": "integer",
						"exclusiveMinimum": 0
					}
				},
				"required": ["type", "host", "value"]
			},
			"AnalyzeDomainInput": {
				"type": "object",
				"properties": {
					"domain": {
						"type": "string",
						"minLength": 3,
						"maxLength": 320,
						"description": "Any domain — or a URL or email address, reduced to its domain. Nothing is saved.",
						"example": "acme.com"
					}
				},
				"required": ["domain"],
				"additionalProperties": false
			},
			"DomainSuggestion": {
				"type": "object",
				"properties": {
					"name": {
						"type": "string",
						"example": "getacme.com"
					},
					"available": {
						"type": "boolean"
					},
					"yearlyPriceUsd": {
						"type": "number",
						"description": "Outvoy's price for a year (and each renewal); absent when unavailable."
					},
					"reason": {
						"type": "string",
						"description": "Why it can't be bought (taken, premium, TLD not sold)."
					}
				},
				"required": ["name", "available"],
				"description": "The name typed, when it is a full domain."
			},
			"DomainReputationDay": {
				"type": "object",
				"properties": {
					"date": {
						"type": "string"
					},
					"score": {
						"type": "integer"
					},
					"level": {
						"type": "string",
						"enum": ["excellent", "good", "fair", "poor", "critical", "unknown"]
					},
					"inboxRate": {
						"type": "number",
						"minimum": 0,
						"maximum": 1
					},
					"checked": {
						"type": "integer"
					}
				},
				"required": ["date", "level", "checked"]
			},
			"DomainOrder": {
				"type": "object",
				"properties": {
					"id": {
						"type": "string",
						"example": "dor_2Kx8Lm0PqRsT4uVwXyZaB"
					},
					"status": {
						"type": "string",
						"enum": [
							"awaiting_payment",
							"provisioning",
							"awaiting_operator",
							"completed",
							"failed",
							"cancelled"
						]
					},
					"statusDetail": {
						"type": "string"
					},
					"provider": {
						"type": "string",
						"enum": ["google_workspace"]
					},
					"redirectUrl": {
						"type": "string",
						"format": "uri"
					},
					"items": {
						"type": "array",
						"items": {
							"$ref": "#/components/schemas/DomainOrderItem"
						}
					},
					"totals": {
						"type": "object",
						"properties": {
							"domainsUsd": {
								"type": "number"
							},
							"mailboxesPerMonthUsd": {
								"type": "number"
							},
							"mailboxes": {
								"type": "integer"
							},
							"dueTodayUsd": {
								"type": "number"
							}
						},
						"required": [
							"domainsUsd",
							"mailboxesPerMonthUsd",
							"mailboxes",
							"dueTodayUsd"
						]
					},
					"createdAt": {
						"type": "string",
						"format": "date-time"
					},
					"paidAt": {
						"type": "string",
						"format": "date-time"
					},
					"completedAt": {
						"type": "string",
						"format": "date-time"
					},
					"updatedAt": {
						"type": "string",
						"format": "date-time"
					}
				},
				"required": [
					"id",
					"status",
					"provider",
					"items",
					"totals",
					"createdAt",
					"updatedAt"
				]
			},
			"DomainOrderItem": {
				"type": "object",
				"properties": {
					"domain": {
						"type": "string",
						"example": "getacme.com"
					},
					"yearlyPriceUsd": {
						"type": "number"
					},
					"domainId": {
						"type": "string"
					},
					"mailboxes": {
						"type": "array",
						"items": {
							"$ref": "#/components/schemas/OrderedMailbox"
						}
					},
					"steps": {
						"type": "array",
						"items": {
							"$ref": "#/components/schemas/DomainOrderStepState"
						}
					}
				},
				"required": ["domain", "yearlyPriceUsd", "mailboxes", "steps"]
			},
			"OrderedMailbox": {
				"type": "object",
				"properties": {
					"email": {
						"type": "string",
						"example": "jamie@getacme.com"
					},
					"firstName": {
						"type": "string"
					},
					"lastName": {
						"type": "string"
					},
					"mailboxId": {
						"type": "string",
						"description": "The mailbox once it is connected."
					}
				},
				"required": ["email", "firstName", "lastName"]
			},
			"DomainOrderStepState": {
				"type": "object",
				"properties": {
					"step": {
						"type": "string",
						"enum": [
							"register_domain",
							"configure_dns",
							"add_to_workspace",
							"create_mailboxes",
							"enable_dkim",
							"connect_mailboxes"
						]
					},
					"status": {
						"type": "string",
						"enum": ["pending", "running", "waiting", "done", "failed"]
					},
					"detail": {
						"type": "string",
						"description": "What is happening or went wrong, in one sentence."
					},
					"attempts": {
						"type": "integer"
					},
					"startedAt": {
						"type": "string",
						"format": "date-time"
					},
					"finishedAt": {
						"type": "string",
						"format": "date-time"
					}
				},
				"required": ["step", "status", "attempts"]
			},
			"CreateDomainOrderInput": {
				"type": "object",
				"properties": {
					"items": {
						"type": "array",
						"items": {
							"type": "object",
							"properties": {
								"domain": {
									"type": "string",
									"minLength": 3,
									"maxLength": 253,
									"example": "getacme.com"
								},
								"mailboxes": {
									"type": "array",
									"items": {
										"type": "object",
										"properties": {
											"localPart": {
												"type": "string",
												"minLength": 1,
												"maxLength": 64,
												"example": "jamie"
											},
											"firstName": {
												"type": "string",
												"minLength": 1,
												"maxLength": 100
											},
											"lastName": {
												"type": "string",
												"minLength": 1,
												"maxLength": 100
											}
										},
										"required": ["localPart", "firstName", "lastName"],
										"additionalProperties": false
									},
									"minItems": 1,
									"maxItems": 5
								}
							},
							"required": ["domain", "mailboxes"],
							"additionalProperties": false
						},
						"minItems": 1,
						"maxItems": 5
					},
					"provider": {
						"type": "string",
						"enum": ["google_workspace"],
						"default": "google_workspace"
					},
					"redirectUrl": {
						"type": "string",
						"maxLength": 2000,
						"format": "uri",
						"description": "Your real website: the new domains redirect there, so a person who types them lands on you."
					},
					"timezone": {
						"type": "string",
						"description": "The mailbox's timezone: warm-up runs in its working hours (default Europe/Madrid).",
						"example": "Europe/Madrid"
					}
				},
				"required": ["items"],
				"additionalProperties": false
			},
			"PlacementTest": {
				"type": "object",
				"properties": {
					"id": {
						"type": "string",
						"example": "plt_9Gh2kLm0PqRsT4uVwXyZc"
					},
					"mailboxId": {
						"type": "string"
					},
					"mailboxEmail": {
						"type": "string"
					},
					"subject": {
						"type": "string"
					},
					"status": {
						"type": "string",
						"enum": ["running", "completed", "failed"]
					},
					"score": {
						"type": "integer",
						"minimum": 0,
						"maximum": 100,
						"description": "Percentage of seeds where it landed in the inbox, once complete."
					},
					"overall": {
						"$ref": "#/components/schemas/PlacementRates"
					},
					"byProvider": {
						"type": "array",
						"items": {
							"type": "object",
							"properties": {
								"provider": {
									"type": "string",
									"enum": ["google", "microsoft", "yahoo", "other"]
								},
								"rates": {
									"$ref": "#/components/schemas/PlacementRates"
								}
							},
							"required": ["provider", "rates"]
						}
					},
					"seeds": {
						"type": "array",
						"items": {
							"$ref": "#/components/schemas/PlacementSeedResult"
						}
					},
					"startedAt": {
						"type": "string",
						"format": "date-time"
					},
					"completedAt": {
						"type": "string",
						"format": "date-time"
					}
				},
				"required": [
					"id",
					"mailboxId",
					"mailboxEmail",
					"subject",
					"status",
					"overall",
					"byProvider",
					"seeds",
					"startedAt"
				]
			},
			"PlacementSeedResult": {
				"type": "object",
				"properties": {
					"seed": {
						"type": "string",
						"description": "A label for the seed mailbox (its provider and number).",
						"example": "Gmail · 1"
					},
					"provider": {
						"type": "string",
						"enum": ["google", "microsoft", "yahoo", "other"]
					},
					"placement": {
						"type": "string",
						"enum": ["inbox", "promotions", "spam", "missing"],
						"description": "Absent while it hasn't been found yet."
					},
					"auth": {
						"$ref": "#/components/schemas/AuthResults"
					},
					"checkedAt": {
						"type": "string",
						"format": "date-time"
					}
				},
				"required": ["seed", "provider"]
			},
			"AuthResults": {
				"type": "object",
				"properties": {
					"spf": {
						"type": "string",
						"enum": [
							"pass",
							"fail",
							"softfail",
							"neutral",
							"none",
							"temperror",
							"permerror"
						]
					},
					"dkim": {
						"type": "string",
						"enum": [
							"pass",
							"fail",
							"softfail",
							"neutral",
							"none",
							"temperror",
							"permerror"
						]
					},
					"dmarc": {
						"type": "string",
						"enum": [
							"pass",
							"fail",
							"softfail",
							"neutral",
							"none",
							"temperror",
							"permerror"
						]
					},
					"dkimDomain": {
						"type": "string",
						"description": "The domain the passing DKIM signature belongs to (d=)."
					},
					"dkimSelector": {
						"type": "string",
						"description": "The selector of that signature (s=), when the provider wrote it."
					}
				},
				"description": "What the receiving provider wrote in Authentication-Results for this message."
			},
			"RunPlacementTestInput": {
				"type": "object",
				"properties": {
					"mailboxId": {
						"type": "string"
					},
					"subject": {
						"type": "string",
						"minLength": 1,
						"maxLength": 200
					},
					"body": {
						"type": "string",
						"minLength": 1,
						"maxLength": 10000,
						"description": "Plain text, exactly as your campaign would send it."
					}
				},
				"required": ["mailboxId", "subject", "body"],
				"additionalProperties": false
			},
			"DeliverabilityOverview": {
				"type": "object",
				"properties": {
					"mailboxes": {
						"type": "object",
						"properties": {
							"total": {
								"type": "integer"
							},
							"byReadiness": {
								"type": "object",
								"properties": {
									"warming": {
										"type": "integer"
									},
									"ready": {
										"type": "integer"
									},
									"limited": {
										"type": "integer"
									},
									"at_risk": {
										"type": "integer"
									},
									"not_warming": {
										"type": "integer"
									},
									"inactive": {
										"type": "integer"
									}
								}
							},
							"warmingUp": {
								"type": "integer",
								"description": "Mailboxes with warm-up on and active."
							}
						},
						"required": ["total", "byReadiness", "warmingUp"]
					},
					"domains": {
						"type": "integer"
					},
					"averageScore": {
						"type": "integer",
						"description": "Mean reputation score of the mailboxes that have one (enough evidence)."
					},
					"placement7d": {
						"$ref": "#/components/schemas/PlacementRates"
					},
					"byProvider": {
						"type": "array",
						"items": {
							"type": "object",
							"properties": {
								"provider": {
									"type": "string",
									"enum": ["google", "microsoft", "yahoo", "other"]
								},
								"rates": {
									"$ref": "#/components/schemas/PlacementRates"
								}
							},
							"required": ["provider", "rates"]
						}
					},
					"days": {
						"type": "array",
						"items": {
							"$ref": "#/components/schemas/DeliverabilityDay"
						},
						"description": "The last 30 local days of warm-up across every mailbox, oldest first."
					},
					"recommendedDailyVolume": {
						"type": "integer",
						"description": "Cold emails a day the workspace's mailboxes can carry now, summed."
					},
					"network": {
						"type": "object",
						"properties": {
							"size": {
								"type": "integer",
								"description": "Mailboxes warming up in the live network (house mailboxes included)."
							},
							"small": {
								"type": "boolean",
								"description": "true while the live network is still small: warm-up works, but placement statistics are less reliable."
							}
						},
						"required": ["size", "small"]
					},
					"attention": {
						"type": "array",
						"items": {
							"$ref": "#/components/schemas/DeliverabilityAttentionItem"
						},
						"description": "What needs someone's attention, most serious first."
					},
					"purchasing": {
						"type": "object",
						"properties": {
							"available": {
								"type": "boolean",
								"description": "Whether domains and mailboxes can be bought through Outvoy on this server. When false, searching and ordering answer 503 EMAIL_INFRASTRUCTURE_NOT_CONFIGURED_ERROR and the console hides the purchase."
							}
						},
						"required": ["available"]
					}
				},
				"required": [
					"mailboxes",
					"domains",
					"placement7d",
					"byProvider",
					"days",
					"recommendedDailyVolume",
					"network",
					"attention",
					"purchasing"
				]
			},
			"DeliverabilityDay": {
				"type": "object",
				"properties": {
					"date": {
						"type": "string",
						"example": "2026-11-02"
					},
					"sent": {
						"type": "integer"
					},
					"inbox": {
						"type": "integer"
					},
					"promotions": {
						"type": "integer"
					},
					"spam": {
						"type": "integer"
					},
					"missing": {
						"type": "integer"
					},
					"repliesSent": {
						"type": "integer"
					},
					"repliesInbox": {
						"type": "integer"
					},
					"repliesSpam": {
						"type": "integer"
					},
					"averageScore": {
						"type": "integer"
					}
				},
				"required": [
					"date",
					"sent",
					"inbox",
					"promotions",
					"spam",
					"missing",
					"repliesSent",
					"repliesInbox",
					"repliesSpam"
				]
			},
			"DeliverabilityAttentionItem": {
				"type": "object",
				"properties": {
					"severity": {
						"type": "string",
						"enum": ["critical", "warning", "info"]
					},
					"kind": {
						"type": "string",
						"enum": [
							"needs_reconnect",
							"at_risk",
							"blocklisted",
							"check_failing",
							"small_network",
							"order_waiting",
							"order_failed"
						]
					},
					"subject": {
						"type": "object",
						"properties": {
							"type": {
								"type": "string",
								"enum": ["mailbox", "domain", "order", "workspace"]
							},
							"id": {
								"type": "string"
							},
							"label": {
								"type": "string",
								"example": "jamie@getacme.com"
							}
						},
						"required": ["type", "label"]
					},
					"title": {
						"type": "string"
					},
					"detail": {
						"type": "string"
					}
				},
				"required": ["severity", "kind", "subject", "title", "detail"]
			},
			"MailboxDailyStat": {
				"type": "object",
				"properties": {
					"date": {
						"type": "string",
						"description": "The mailbox's local date (YYYY-MM-DD).",
						"example": "2026-11-02"
					},
					"sent": {
						"type": "integer",
						"description": "Warm-up emails it sent that day (new and replies)."
					},
					"inbox": {
						"type": "integer"
					},
					"promotions": {
						"type": "integer"
					},
					"spam": {
						"type": "integer"
					},
					"missing": {
						"type": "integer"
					},
					"rescued": {
						"type": "integer",
						"description": "Of its emails found in spam, how many the network moved to the inbox."
					},
					"received": {
						"type": "integer"
					},
					"repliesReceived": {
						"type": "integer"
					},
					"score": {
						"type": "integer",
						"description": "The reputation score at the end of that day."
					}
				},
				"required": [
					"date",
					"sent",
					"inbox",
					"promotions",
					"spam",
					"missing",
					"rescued",
					"received",
					"repliesReceived"
				]
			},
			"WarmupActivity": {
				"type": "object",
				"properties": {
					"id": {
						"type": "string"
					},
					"direction": {
						"type": "string",
						"enum": ["sent", "received"]
					},
					"kind": {
						"type": "string",
						"enum": ["initial", "reply", "placement_test"]
					},
					"status": {
						"type": "string",
						"enum": ["planned", "sent", "failed", "cancelled"]
					},
					"subject": {
						"type": "string"
					},
					"counterpartProvider": {
						"type": "string",
						"enum": ["google", "microsoft", "yahoo", "other"],
						"description": "The other mailbox's provider. Who it is stays private to its workspace."
					},
					"placement": {
						"type": "string",
						"enum": ["inbox", "promotions", "spam", "missing"],
						"description": "Where it landed (sent messages, once checked)."
					},
					"rescued": {
						"type": "boolean"
					},
					"replied": {
						"type": "boolean"
					},
					"at": {
						"type": "string",
						"format": "date-time",
						"description": "When it was sent, or is planned."
					},
					"checkedAt": {
						"type": "string",
						"format": "date-time"
					}
				},
				"required": [
					"id",
					"direction",
					"kind",
					"status",
					"subject",
					"counterpartProvider",
					"rescued",
					"replied",
					"at"
				]
			},
			"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 their path through the workflow ran to its end; not_accepted when it ended because the invitation was withdrawn unanswered."
					},
					"outcome": {
						"type": "string",
						"description": "The outcome named by the end step they reached, when it names one.",
						"example": "not a fit"
					}
				},
				"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
			},
			"MailboxEventData": {
				"type": "object",
				"properties": {
					"mailboxId": {
						"type": "string",
						"example": "mbx_4kQ8wT1zLm0PqRsT7uVwX"
					},
					"email": {
						"type": "string",
						"example": "jamie@getacme.com"
					},
					"provider": {
						"type": "string",
						"enum": ["google", "microsoft", "imap", "sandbox"]
					},
					"origin": {
						"type": "string",
						"enum": ["connected", "purchased", "sandbox"]
					},
					"status": {
						"type": "string",
						"enum": [
							"provisioning",
							"active",
							"paused",
							"needs_reconnect",
							"cancelling",
							"disconnected"
						]
					},
					"statusDetail": {
						"type": "string"
					},
					"reconnected": {
						"type": "boolean",
						"description": "mailbox.connected: an existing mailbox got its access back."
					}
				},
				"required": ["mailboxId", "email", "provider", "origin", "status"],
				"additionalProperties": false
			},
			"MailboxReputationChangedEventData": {
				"type": "object",
				"properties": {
					"mailboxId": {
						"type": "string",
						"example": "mbx_4kQ8wT1zLm0PqRsT7uVwX"
					},
					"email": {
						"type": "string",
						"example": "jamie@getacme.com"
					},
					"provider": {
						"type": "string",
						"enum": ["google", "microsoft", "imap", "sandbox"]
					},
					"origin": {
						"type": "string",
						"enum": ["connected", "purchased", "sandbox"]
					},
					"score": {
						"type": "integer"
					},
					"level": {
						"type": "string",
						"enum": ["excellent", "good", "fair", "poor", "critical", "unknown"]
					},
					"previousLevel": {
						"type": "string",
						"enum": ["excellent", "good", "fair", "poor", "critical", "unknown"]
					},
					"readiness": {
						"type": "string",
						"enum": [
							"warming",
							"ready",
							"limited",
							"at_risk",
							"not_warming",
							"inactive"
						]
					},
					"previousReadiness": {
						"type": "string",
						"enum": [
							"warming",
							"ready",
							"limited",
							"at_risk",
							"not_warming",
							"inactive"
						]
					},
					"recommendedDailyVolume": {
						"type": "integer"
					},
					"summary": {
						"type": "string"
					}
				},
				"required": [
					"mailboxId",
					"email",
					"provider",
					"origin",
					"level",
					"previousLevel",
					"readiness",
					"previousReadiness",
					"recommendedDailyVolume",
					"summary"
				],
				"additionalProperties": false
			},
			"MailboxReadyEventData": {
				"type": "object",
				"properties": {
					"mailboxId": {
						"type": "string",
						"example": "mbx_4kQ8wT1zLm0PqRsT7uVwX"
					},
					"email": {
						"type": "string",
						"example": "jamie@getacme.com"
					},
					"provider": {
						"type": "string",
						"enum": ["google", "microsoft", "imap", "sandbox"]
					},
					"origin": {
						"type": "string",
						"enum": ["connected", "purchased", "sandbox"]
					},
					"score": {
						"type": "integer"
					},
					"level": {
						"type": "string",
						"enum": ["excellent", "good", "fair", "poor", "critical", "unknown"]
					},
					"recommendedDailyVolume": {
						"type": "integer"
					},
					"warmupDay": {
						"type": "integer"
					}
				},
				"required": [
					"mailboxId",
					"email",
					"provider",
					"origin",
					"level",
					"recommendedDailyVolume",
					"warmupDay"
				],
				"additionalProperties": false
			},
			"DomainHealthChangedEventData": {
				"type": "object",
				"properties": {
					"domainId": {
						"type": "string",
						"example": "dom_7Hj2kLm0PqRsT4uVwXyZb"
					},
					"domain": {
						"type": "string",
						"example": "getacme.com"
					},
					"setupScore": {
						"type": "integer"
					},
					"changes": {
						"type": "array",
						"items": {
							"type": "object",
							"properties": {
								"check": {
									"type": "string",
									"enum": [
										"mx",
										"spf",
										"dkim",
										"dmarc",
										"blocklists",
										"domain_age",
										"website",
										"mta_sts",
										"tls_rpt",
										"bimi",
										"reverse_dns"
									]
								},
								"from": {
									"type": "string",
									"enum": ["pass", "warn", "fail", "info", "unknown"]
								},
								"to": {
									"type": "string",
									"enum": ["pass", "warn", "fail", "info", "unknown"]
								},
								"summary": {
									"type": "string"
								}
							},
							"required": ["check", "to", "summary"]
						}
					}
				},
				"required": ["domainId", "domain", "setupScore", "changes"],
				"additionalProperties": false
			},
			"DomainBlocklistEventData": {
				"type": "object",
				"properties": {
					"domainId": {
						"type": "string",
						"example": "dom_7Hj2kLm0PqRsT4uVwXyZb"
					},
					"domain": {
						"type": "string",
						"example": "getacme.com"
					},
					"lists": {
						"type": "array",
						"items": {
							"type": "string"
						},
						"description": "The blocklists that list it now (blocklisted) or no longer list it (delisted).",
						"example": ["Spamhaus DBL"]
					}
				},
				"required": ["domainId", "domain", "lists"],
				"additionalProperties": false
			},
			"DomainOrderEventData": {
				"type": "object",
				"properties": {
					"orderId": {
						"type": "string",
						"example": "dor_2Kx8Lm0PqRsT4uVwXyZaB"
					},
					"domains": {
						"type": "array",
						"items": {
							"type": "string"
						}
					},
					"mailboxes": {
						"type": "array",
						"items": {
							"type": "object",
							"properties": {
								"email": {
									"type": "string"
								},
								"mailboxId": {
									"type": "string"
								}
							},
							"required": ["email"]
						}
					},
					"detail": {
						"type": "string"
					}
				},
				"required": ["orderId", "domains", "mailboxes"],
				"additionalProperties": false
			},
			"PlacementTestCompletedEventData": {
				"type": "object",
				"properties": {
					"testId": {
						"type": "string",
						"example": "plt_9Gh2kLm0PqRsT4uVwXyZc"
					},
					"mailboxId": {
						"type": "string"
					},
					"email": {
						"type": "string"
					},
					"score": {
						"type": "integer",
						"description": "Percentage of seeds where it landed in the inbox."
					},
					"seeds": {
						"type": "integer"
					},
					"inbox": {
						"type": "integer"
					},
					"promotions": {
						"type": "integer"
					},
					"spam": {
						"type": "integer"
					},
					"missing": {
						"type": "integer"
					}
				},
				"required": [
					"testId",
					"mailboxId",
					"email",
					"score",
					"seeds",
					"inbox",
					"promotions",
					"spam",
					"missing"
				],
				"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_PAYMENT_FAILED_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",
							"DKIM_NOT_AWAITED_ERROR",
							"DOMAIN_ANALYSIS_LIMIT_ERROR",
							"DOMAIN_CHECK_TOO_SOON_ERROR",
							"DOMAIN_NOT_OFFERED_ERROR",
							"EMAIL_ALREADY_REGISTERED_ERROR",
							"EMAIL_INFRASTRUCTURE_NOT_CONFIGURED_ERROR",
							"EMAIL_NOT_CONFIGURED_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_DKIM_RECORD_ERROR",
							"INVALID_DOMAIN_ERROR",
							"INVALID_DOMAIN_ORDER_ERROR",
							"INVALID_LINKEDIN_PROFILE_ERROR",
							"INVALID_MAILBOX_ADDRESS_ERROR",
							"INVALID_OAUTH_STATE_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_ALREADY_IN_USE_ERROR",
							"LINKEDIN_ACCOUNT_NOT_FOUND_ERROR",
							"LINKEDIN_ACCOUNT_NOT_READY_ERROR",
							"LINKEDIN_ACTION_FAILED_ERROR",
							"LINKEDIN_CHECKPOINT_REQUIRED_ERROR",
							"LINKEDIN_NOT_CONFIGURED_ERROR",
							"LINKEDIN_REQUEST_FAILED_ERROR",
							"LINKEDIN_SESSION_INVALID_ERROR",
							"MAILBOXES_NOT_SOLD_ERROR",
							"MAILBOX_ALREADY_CONNECTED_ERROR",
							"MAILBOX_CONNECTION_FAILED_ERROR",
							"MAILBOX_NOT_ACTIVE_ERROR",
							"MAILBOX_NOT_RECONNECTABLE_ERROR",
							"MAILBOX_ORDER_PAYMENT_FAILED_ERROR",
							"MAILBOX_PAYMENT_REQUIRED_ERROR",
							"MAILBOX_PLAN_LIMIT_ERROR",
							"MAIL_SERVER_NOT_ALLOWED_ERROR",
							"NOT_IN_TRIAL_ERROR",
							"NO_BILLING_ACCOUNT_ERROR",
							"NO_LIVE_SUBSCRIPTION_ERROR",
							"PLACEMENT_SEEDS_NOT_CONFIGURED_ERROR",
							"PLACEMENT_TEST_LIMIT_ERROR",
							"PLAN_LIMIT_REACHED_ERROR",
							"PLAN_REQUIRED_ERROR",
							"PROVIDER_EMAIL_HAS_PASSWORD_ACCOUNT_ERROR",
							"PROVIDER_EMAIL_NOT_VERIFIED_ERROR",
							"PROVIDER_REQUEST_FAILED_ERROR",
							"PROVIDER_SIGN_IN_FAILED_ERROR",
							"PROVIDER_SIGN_IN_REJECTED_ERROR",
							"RETENTION_OFFER_NOT_AVAILABLE_ERROR",
							"SENDER_DAILY_MESSAGE_CAP_REACHED_ERROR",
							"SENDER_LIMIT_EXCEEDED_ERROR",
							"SENDER_NOT_ACTIVE_ERROR",
							"SENDER_NOT_RECONNECTABLE_ERROR",
							"SESSION_REQUIRED_ERROR",
							"SIGN_IN_PROVIDER_NOT_CONFIGURED_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."
					}
				}
			}
		},
		"mailbox.connected": {
			"post": {
				"operationId": "mailboxConnectedEvent",
				"summary": "mailbox.connected",
				"tags": ["Events"],
				"description": "Delivered to every enabled webhook endpoint that wants mailbox.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": "mailbox.connected"
									},
									"occurredAt": {
										"type": "string",
										"format": "date-time"
									},
									"data": {
										"$ref": "#/components/schemas/MailboxEventData"
									}
								},
								"required": ["id", "type", "occurredAt", "data"]
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Any 2xx within 10 s acknowledges; anything else is retried."
					}
				}
			}
		},
		"mailbox.needs_reconnect": {
			"post": {
				"operationId": "mailboxNeedsReconnectEvent",
				"summary": "mailbox.needs_reconnect",
				"tags": ["Events"],
				"description": "Delivered to every enabled webhook endpoint that wants mailbox.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": "mailbox.needs_reconnect"
									},
									"occurredAt": {
										"type": "string",
										"format": "date-time"
									},
									"data": {
										"$ref": "#/components/schemas/MailboxEventData"
									}
								},
								"required": ["id", "type", "occurredAt", "data"]
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Any 2xx within 10 s acknowledges; anything else is retried."
					}
				}
			}
		},
		"mailbox.reputation_changed": {
			"post": {
				"operationId": "mailboxReputationChangedEvent",
				"summary": "mailbox.reputation_changed",
				"tags": ["Events"],
				"description": "Delivered to every enabled webhook endpoint that wants mailbox.reputation_changed, 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": "mailbox.reputation_changed"
									},
									"occurredAt": {
										"type": "string",
										"format": "date-time"
									},
									"data": {
										"$ref": "#/components/schemas/MailboxReputationChangedEventData"
									}
								},
								"required": ["id", "type", "occurredAt", "data"]
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Any 2xx within 10 s acknowledges; anything else is retried."
					}
				}
			}
		},
		"mailbox.ready": {
			"post": {
				"operationId": "mailboxReadyEvent",
				"summary": "mailbox.ready",
				"tags": ["Events"],
				"description": "Delivered to every enabled webhook endpoint that wants mailbox.ready, 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": "mailbox.ready"
									},
									"occurredAt": {
										"type": "string",
										"format": "date-time"
									},
									"data": {
										"$ref": "#/components/schemas/MailboxReadyEventData"
									}
								},
								"required": ["id", "type", "occurredAt", "data"]
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Any 2xx within 10 s acknowledges; anything else is retried."
					}
				}
			}
		},
		"domain.health_changed": {
			"post": {
				"operationId": "domainHealthChangedEvent",
				"summary": "domain.health_changed",
				"tags": ["Events"],
				"description": "Delivered to every enabled webhook endpoint that wants domain.health_changed, 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": "domain.health_changed"
									},
									"occurredAt": {
										"type": "string",
										"format": "date-time"
									},
									"data": {
										"$ref": "#/components/schemas/DomainHealthChangedEventData"
									}
								},
								"required": ["id", "type", "occurredAt", "data"]
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Any 2xx within 10 s acknowledges; anything else is retried."
					}
				}
			}
		},
		"domain.blocklisted": {
			"post": {
				"operationId": "domainBlocklistedEvent",
				"summary": "domain.blocklisted",
				"tags": ["Events"],
				"description": "Delivered to every enabled webhook endpoint that wants domain.blocklisted, 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": "domain.blocklisted"
									},
									"occurredAt": {
										"type": "string",
										"format": "date-time"
									},
									"data": {
										"$ref": "#/components/schemas/DomainBlocklistEventData"
									}
								},
								"required": ["id", "type", "occurredAt", "data"]
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Any 2xx within 10 s acknowledges; anything else is retried."
					}
				}
			}
		},
		"domain.delisted": {
			"post": {
				"operationId": "domainDelistedEvent",
				"summary": "domain.delisted",
				"tags": ["Events"],
				"description": "Delivered to every enabled webhook endpoint that wants domain.delisted, 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": "domain.delisted"
									},
									"occurredAt": {
										"type": "string",
										"format": "date-time"
									},
									"data": {
										"$ref": "#/components/schemas/DomainBlocklistEventData"
									}
								},
								"required": ["id", "type", "occurredAt", "data"]
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Any 2xx within 10 s acknowledges; anything else is retried."
					}
				}
			}
		},
		"domain_order.completed": {
			"post": {
				"operationId": "domainOrderCompletedEvent",
				"summary": "domain_order.completed",
				"tags": ["Events"],
				"description": "Delivered to every enabled webhook endpoint that wants domain_order.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": "domain_order.completed"
									},
									"occurredAt": {
										"type": "string",
										"format": "date-time"
									},
									"data": {
										"$ref": "#/components/schemas/DomainOrderEventData"
									}
								},
								"required": ["id", "type", "occurredAt", "data"]
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Any 2xx within 10 s acknowledges; anything else is retried."
					}
				}
			}
		},
		"domain_order.failed": {
			"post": {
				"operationId": "domainOrderFailedEvent",
				"summary": "domain_order.failed",
				"tags": ["Events"],
				"description": "Delivered to every enabled webhook endpoint that wants domain_order.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": "domain_order.failed"
									},
									"occurredAt": {
										"type": "string",
										"format": "date-time"
									},
									"data": {
										"$ref": "#/components/schemas/DomainOrderEventData"
									}
								},
								"required": ["id", "type", "occurredAt", "data"]
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Any 2xx within 10 s acknowledges; anything else is retried."
					}
				}
			}
		},
		"placement_test.completed": {
			"post": {
				"operationId": "placementTestCompletedEvent",
				"summary": "placement_test.completed",
				"tags": ["Events"],
				"description": "Delivered to every enabled webhook endpoint that wants placement_test.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": "placement_test.completed"
									},
									"occurredAt": {
										"type": "string",
										"format": "date-time"
									},
									"data": {
										"$ref": "#/components/schemas/PlacementTestCompletedEventData"
									}
								},
								"required": ["id", "type", "occurredAt", "data"]
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Any 2xx within 10 s acknowledges; anything else is retried."
					}
				}
			}
		}
	}
}
