{
  "openapi": "3.1.0",
  "info": { "title": "Catchment CRM API", "version": "v1", "description": "Workspace-scoped API for agents and integrations. All responses use JSON." },
  "servers": [{ "url": "https://{host}", "variables": { "host": { "default": "your-catchment-host" } } }],
  "security": [{ "bearerAuth": [] }],
  "components": {
    "securitySchemes": { "bearerAuth": { "type": "http", "scheme": "bearer", "bearerFormat": "Catchment API key" } },
    "parameters": {
      "limit": { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 25 } },
      "cursor": { "name": "cursor", "in": "query", "schema": { "type": "string" } },
      "direction": { "name": "direction", "in": "query", "schema": { "type": "string", "enum": ["asc", "desc"] } },
      "fields": { "name": "fields", "in": "query", "description": "Comma-separated allowlisted sparse fieldset.", "schema": { "type": "string" } }
    },
    "schemas": {
      "Error": { "type": "object", "required": ["error"], "properties": { "error": { "type": "object", "required": ["code", "message"], "properties": { "code": { "type": "string" }, "message": { "type": "string" }, "details": { "type": "object", "additionalProperties": true } } } } },
      "ContactInput": { "type": "object", "required": ["firstName"], "properties": { "firstName": { "type": "string" }, "lastName": { "type": "string" }, "email": { "type": "string", "format": "email" }, "phone": { "type": "string" }, "companyId": { "type": ["string", "null"] }, "ownerId": { "type": ["string", "null"] }, "lifecycleStage": { "type": "string" }, "tags": { "type": "array", "items": { "type": "string" } }, "externalIds": { "type": "object", "additionalProperties": { "type": "string" } } } },
      "ApifyImportInput": { "type": "object", "required": ["channel", "items"], "properties": { "channel": { "type": "string", "examples": ["linkedin", "instagram"] }, "items": { "type": "array", "minItems": 1, "maxItems": 100, "items": { "type": "object", "additionalProperties": true } }, "actorId": { "type": ["string", "null"] }, "actorRunId": { "type": ["string", "null"] }, "datasetId": { "type": ["string", "null"] }, "capturedAt": { "type": ["string", "null"], "format": "date-time" } } },
      "CompanyInput": { "type": "object", "required": ["name"], "properties": { "name": { "type": "string" }, "domain": { "type": ["string", "null"] }, "ownerId": { "type": ["string", "null"] }, "tags": { "type": "array", "items": { "type": "string" } }, "externalIds": { "type": "object", "additionalProperties": { "type": "string" } } } },
      "DealInput": { "type": "object", "required": ["name", "pipelineId", "stageId"], "properties": { "name": { "type": "string" }, "pipelineId": { "type": "string" }, "stageId": { "type": "string" }, "amount": { "type": ["number", "null"] }, "companyId": { "type": ["string", "null"] }, "contactIds": { "type": "array", "items": { "type": "string" } }, "ownerId": { "type": ["string", "null"] } } },
      "TaskInput": { "type": "object", "required": ["title"], "properties": { "title": { "type": "string" }, "assigneeId": { "type": ["string", "null"] }, "dueAt": { "type": ["string", "null"], "format": "date-time" }, "priority": { "type": "string", "enum": ["low", "medium", "high", "urgent"] } } },
      "WebhookInput": { "type": "object", "required": ["url", "events"], "properties": { "url": { "type": "string", "format": "uri", "description": "Public HTTPS URL" }, "events": { "type": "array", "items": { "type": "string", "enum": ["contact.created", "contact.updated", "company.created", "company.updated", "deal.created", "deal.stage_changed", "activity.created", "task.created", "task.updated", "ownership.changed"] } } } }
    }
  },
  "paths": {
    "/api/v1/contacts": { "get": { "summary": "List contacts", "parameters": [{ "$ref": "#/components/parameters/limit" }, { "$ref": "#/components/parameters/cursor" }, { "$ref": "#/components/parameters/direction" }, { "$ref": "#/components/parameters/fields" }], "responses": { "200": { "description": "Cursor page" } } }, "post": { "summary": "Create contact", "parameters": [{ "name": "Idempotency-Key", "in": "header", "schema": { "type": "string" } }], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ContactInput" } } } }, "responses": { "201": { "description": "Created" }, "400": { "description": "Validation error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } },
    "/api/v1/contacts/{contactId}": { "get": { "summary": "Get contact", "parameters": [{ "name": "contactId", "in": "path", "required": true, "schema": { "type": "string" } }], "responses": { "200": { "description": "Contact" }, "404": { "description": "Not found" } } }, "patch": { "summary": "Update contact", "parameters": [{ "name": "contactId", "in": "path", "required": true, "schema": { "type": "string" } }, { "name": "Idempotency-Key", "in": "header", "schema": { "type": "string" } }], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ContactInput" } } } }, "responses": { "200": { "description": "Updated" }, "404": { "description": "Not found" } } } },
    "/api/v1/contacts/bulk": { "post": { "summary": "Bulk create or upsert contacts", "description": "Requires X-Catchment-Approval: bulk-contact-mutation.", "parameters": [{ "name": "X-Catchment-Approval", "in": "header", "required": true, "schema": { "type": "string", "example": "bulk-contact-mutation" } }], "responses": { "207": { "description": "Per-item outcomes" }, "409": { "description": "Approval required" } } } },
    "/api/v1/imports/apify": { "post": { "summary": "Import channel profiles from an Apify execution", "description": "Requires contacts:write and companies:write. Idempotently upserts contacts and current LinkedIn companies, links both records, promotes table-friendly channel fields, and preserves the source item with execution provenance.", "parameters": [{ "name": "Idempotency-Key", "in": "header", "schema": { "type": "string" } }], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApifyImportInput" } } } }, "responses": { "200": { "description": "All profiles and companies imported" }, "207": { "description": "Import completed with per-item failures" }, "400": { "description": "Validation error" } } } },
    "/api/v1/companies": { "get": { "summary": "List companies", "parameters": [{ "$ref": "#/components/parameters/limit" }, { "$ref": "#/components/parameters/cursor" }, { "$ref": "#/components/parameters/fields" }], "responses": { "200": { "description": "Cursor page" } } }, "post": { "summary": "Create company", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CompanyInput" } } } }, "responses": { "201": { "description": "Created" } } } },
    "/api/v1/companies/{companyId}": { "get": { "summary": "Get company", "parameters": [{ "name": "companyId", "in": "path", "required": true, "schema": { "type": "string" } }], "responses": { "200": { "description": "Company" }, "404": { "description": "Not found" } } }, "patch": { "summary": "Update company", "parameters": [{ "name": "companyId", "in": "path", "required": true, "schema": { "type": "string" } }, { "name": "Idempotency-Key", "in": "header", "schema": { "type": "string" } }], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CompanyInput" } } } }, "responses": { "200": { "description": "Updated" }, "404": { "description": "Not found" } } } },
    "/api/v1/companies/{companyId}/relationships": { "get": { "summary": "Read company relationships", "responses": { "200": { "description": "Company with linked contacts and deals" } } }, "patch": { "summary": "Link contacts and deals to a company", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "contactIds": { "type": "array", "items": { "type": "string" } }, "dealIds": { "type": "array", "items": { "type": "string" } }, "ownerId": { "type": ["string", "null"] } } } } } }, "responses": { "200": { "description": "Linked" } } } },
    "/api/v1/deals": { "get": { "summary": "List deals", "parameters": [{ "$ref": "#/components/parameters/limit" }, { "$ref": "#/components/parameters/cursor" }, { "$ref": "#/components/parameters/fields" }], "responses": { "200": { "description": "Cursor page" } } }, "post": { "summary": "Create deal", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DealInput" } } } }, "responses": { "201": { "description": "Created" } } } },
    "/api/v1/deals/{dealId}": { "get": { "summary": "Get deal", "parameters": [{ "name": "dealId", "in": "path", "required": true, "schema": { "type": "string" } }], "responses": { "200": { "description": "Deal" }, "404": { "description": "Not found" } } }, "patch": { "summary": "Update deal", "parameters": [{ "name": "dealId", "in": "path", "required": true, "schema": { "type": "string" } }, { "name": "Idempotency-Key", "in": "header", "schema": { "type": "string" } }], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DealInput" } } } }, "responses": { "200": { "description": "Updated" }, "404": { "description": "Not found" } } } },
    "/api/v1/deals/{dealId}/stage": { "post": { "summary": "Move a deal stage", "description": "Closing a deal requires X-Catchment-Approval: close-deal:{dealId}.", "responses": { "200": { "description": "Moved" }, "409": { "description": "Approval required" } } } },
    "/api/v1/tasks": { "get": { "summary": "List tasks", "parameters": [{ "$ref": "#/components/parameters/limit" }, { "$ref": "#/components/parameters/cursor" }, { "$ref": "#/components/parameters/fields" }], "responses": { "200": { "description": "Cursor page" } } }, "post": { "summary": "Create task", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TaskInput" } } } }, "responses": { "201": { "description": "Created" } } } },
    "/api/v1/tasks/{taskId}": { "get": { "summary": "Get task", "parameters": [{ "name": "taskId", "in": "path", "required": true, "schema": { "type": "string" } }], "responses": { "200": { "description": "Task" }, "404": { "description": "Not found" } } }, "patch": { "summary": "Update task", "parameters": [{ "name": "taskId", "in": "path", "required": true, "schema": { "type": "string" } }, { "name": "Idempotency-Key", "in": "header", "schema": { "type": "string" } }], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TaskInput" } } } }, "responses": { "200": { "description": "Updated" }, "404": { "description": "Not found" } } } },
    "/api/v1/activities": { "get": { "summary": "List activities", "responses": { "200": { "description": "Cursor page" } } }, "post": { "summary": "Log activity", "responses": { "201": { "description": "Created" } } } },
    "/api/v1/pipelines": { "get": { "summary": "List pipelines", "responses": { "200": { "description": "Cursor page" } } } },
    "/api/v1/search": { "get": { "summary": "Prefix-search CRM records", "parameters": [{ "name": "q", "in": "query", "required": true, "schema": { "type": "string", "minLength": 2 } }, { "name": "types", "in": "query", "schema": { "type": "string", "example": "contacts,companies" } }], "responses": { "200": { "description": "Typed search results" } } } },
    "/api/v1/webhooks": { "get": { "summary": "List webhook subscriptions", "responses": { "200": { "description": "Subscriptions without secrets" } } }, "post": { "summary": "Create webhook subscription", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WebhookInput" } } } }, "responses": { "201": { "description": "Created; raw signing secret is returned only once" } } } },
    "/api/v1/webhooks/{webhookId}": { "delete": { "summary": "Delete webhook subscription", "parameters": [{ "name": "webhookId", "in": "path", "required": true, "schema": { "type": "string" } }], "responses": { "204": { "description": "Deleted" } } } },
    "/api/v1/api-keys": { "get": { "summary": "List workspace API keys", "description": "Requires a Firebase user bearer token from a workspace owner or admin. Secrets are never returned.", "parameters": [{ "name": "workspaceId", "in": "query", "required": true, "schema": { "type": "string" } }], "responses": { "200": { "description": "Safe key metadata" }, "403": { "description": "Forbidden" } } }, "post": { "summary": "Create a workspace API key", "description": "Requires a Firebase user bearer token from a workspace owner or admin.", "responses": { "201": { "description": "Created; raw API key returned only once" }, "403": { "description": "Forbidden" } } }, "delete": { "summary": "Revoke a workspace API key", "parameters": [{ "name": "workspaceId", "in": "query", "required": true, "schema": { "type": "string" } }, { "name": "keyId", "in": "query", "required": true, "schema": { "type": "string" } }], "responses": { "204": { "description": "Revoked" }, "403": { "description": "Forbidden" } } } }
  }
}
