{
  "openapi": "3.1.0",
  "info": {
    "version": "2.0.0",
    "title": "ABM.dev API",
    "description": "GTM Intelligence API - Enrichment, LinkedIn research, CRM integration, and account management.",
    "contact": {
      "name": "ABM.dev",
      "url": "https://abm.dev"
    }
  },
  "servers": [
    {
      "url": "https://api.abm.dev",
      "description": "Production"
    },
    {
      "url": "https://api-dev.abm.dev",
      "description": "Staging"
    }
  ],
  "tags": [
    {
      "name": "Enrichment",
      "description": "Core enrichment operations - enrich persons and companies with data from multiple sources"
    },
    {
      "name": "LinkedIn",
      "description": "LinkedIn research, engagement, and outreach via Voyager API"
    },
    {
      "name": "CRM",
      "description": "CRM integration configuration and field mappings"
    },
    {
      "name": "Organization",
      "description": "Account and workspace management"
    },
    {
      "name": "Health",
      "description": "System health monitoring"
    },
    {
      "name": "People Finder",
      "description": "Find decision-makers at target companies by role — powered by multi-source search and optional enrichment"
    },
    {
      "name": "Campaigns",
      "description": "Orchestrate multi-step outreach campaigns that combine people-finding, enrichment, and CRM writeback"
    },
    {
      "name": "Field Configuration",
      "description": "Configure which enrichment fields are enabled, required, or mapped to CRM properties"
    },
    {
      "name": "Enrichment Config",
      "description": "Global enrichment settings — source priority, auto-approval, writeback behavior"
    },
    {
      "name": "Webhooks",
      "description": "Subscribe to real-time event notifications for enrichments, campaigns, and system events"
    }
  ],
  "x-tagGroups": [
    {
      "name": "Core API",
      "tags": ["Enrichment", "People Finder", "Campaigns"]
    },
    {
      "name": "Configuration",
      "tags": ["Field Configuration", "Enrichment Config"]
    },
    {
      "name": "Integrations",
      "tags": ["LinkedIn", "CRM", "Webhooks"]
    },
    {
      "name": "Account",
      "tags": ["Organization", "Health"]
    }
  ],
  "security": [
    {
      "ApiKeyAuth": []
    }
  ],
  "paths": {
    "/v1/enrichments": {
      "post": {
        "operationId": "createEnrichment",
        "tags": ["Enrichment"],
        "summary": "Create enrichment",
        "description": "Submit a new enrichment request. Returns 202 while processing completes asynchronously.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["type", "input"],
                "properties": {
                  "type": {
                    "type": "string",
                    "enum": ["person"],
                    "description": "Entity type to enrich"
                  },
                  "input": {
                    "$ref": "#/components/schemas/EnrichmentInput"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Enrichment accepted for processing",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnrichmentSummary"
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      },
      "get": {
        "operationId": "listEnrichments",
        "tags": ["Enrichment"],
        "summary": "List enrichments",
        "parameters": [
          { "name": "status", "in": "query", "schema": { "type": "string" } },
          { "name": "skip", "in": "query", "schema": { "type": "integer", "default": 0 }, "description": "Number of records to skip" },
          { "name": "take", "in": "query", "schema": { "type": "integer", "default": 20 }, "description": "Number of records to return" }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of enrichments",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": { "type": "array", "items": { "$ref": "#/components/schemas/EnrichmentSummary" } },
                    "total": { "type": "integer" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/enrichments/stats": {
      "get": {
        "operationId": "getEnrichmentStats",
        "tags": ["Enrichment"],
        "summary": "Get enrichment statistics",
        "responses": {
          "200": {
            "description": "Enrichment statistics",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "total": { "type": "integer" },
                    "by_status": { "type": "object", "additionalProperties": { "type": "integer" } },
                    "by_source": { "type": "object", "additionalProperties": { "type": "integer" } }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/enrichments/{id}": {
      "get": {
        "operationId": "getEnrichment",
        "tags": ["Enrichment"],
        "summary": "Get enrichment by ID",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }
        ],
        "responses": {
          "200": {
            "description": "Enrichment with result data",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/EnrichmentResult" }
              }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      },
      "delete": {
        "operationId": "cancelEnrichment",
        "tags": ["Enrichment"],
        "summary": "Cancel enrichment",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }
        ],
        "responses": {
          "204": { "description": "Enrichment cancelled" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/enrichments/{id}/stream": {
      "get": {
        "operationId": "streamEnrichment",
        "tags": ["Enrichment"],
        "summary": "Stream enrichment progress via SSE",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }
        ],
        "responses": {
          "200": {
            "description": "Server-Sent Events stream",
            "content": {
              "text/event-stream": {
                "schema": { "type": "string" }
              }
            }
          }
        }
      }
    },
    "/v1/enrichments/{id}/approve": {
      "post": {
        "operationId": "approveEnrichment",
        "tags": ["Enrichment"],
        "summary": "Approve enrichment and trigger CRM writeback",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "field_overrides": { "type": "object", "additionalProperties": true }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Enrichment approved and CRM writeback initiated" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/enrichments/{id}/sources": {
      "get": {
        "operationId": "getEnrichmentSources",
        "tags": ["Enrichment"],
        "summary": "Get source breakdown for enrichment",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }
        ],
        "responses": {
          "200": { "description": "Source attribution breakdown" }
        }
      }
    },
    "/v1/enrichments/{id}/fields": {
      "get": {
        "operationId": "getEnrichmentFields",
        "tags": ["Enrichment"],
        "summary": "Get field attribution for enrichment",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }
        ],
        "responses": {
          "200": { "description": "Field-level source attribution" }
        }
      }
    },
    "/v1/enrichments/{id}/writeback-preview": {
      "get": {
        "operationId": "getWritebackPreview",
        "tags": ["Enrichment"],
        "summary": "Preview CRM diff before writeback",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }
        ],
        "responses": {
          "200": { "description": "CRM field diff preview" }
        }
      }
    },
    "/v1/enrichments/{id}/export/excel": {
      "get": {
        "operationId": "exportEnrichmentExcel",
        "tags": ["Enrichment"],
        "summary": "Export enrichment as Excel",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }
        ],
        "responses": {
          "200": {
            "description": "Excel file download",
            "content": {
              "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": {
                "schema": { "type": "string", "format": "binary" }
              }
            }
          }
        }
      }
    },
    "/v1/enrichments/batches/preview": {
      "post": {
        "operationId": "previewBatch",
        "tags": ["Enrichment"],
        "summary": "Preview a batch enrichment",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["list_id", "platform"],
                "properties": {
                  "list_id": { "type": "string" },
                  "platform": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Batch preview with member count and credit estimate" }
        }
      }
    },
    "/v1/enrichments/batches/confirm": {
      "post": {
        "operationId": "confirmBatch",
        "tags": ["Enrichment"],
        "summary": "Confirm and start a batch enrichment",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["batch_id"],
                "properties": {
                  "batch_id": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": {
          "202": { "description": "Batch confirmed and processing started" }
        }
      }
    },
    "/v1/enrichments/batches": {
      "get": {
        "operationId": "listBatches",
        "tags": ["Enrichment"],
        "summary": "List enrichment batches",
        "responses": {
          "200": { "description": "List of enrichment batches" }
        }
      }
    },
    "/v1/enrichments/batches/{batchId}": {
      "get": {
        "operationId": "getBatch",
        "tags": ["Enrichment"],
        "summary": "Get enrichment batch",
        "parameters": [
          { "name": "batchId", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": {
          "200": { "description": "Batch details with status and progress" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/enrichments/batches/{batchId}/members": {
      "get": {
        "operationId": "getBatchMembers",
        "tags": ["Enrichment"],
        "summary": "Get batch members",
        "parameters": [
          { "name": "batchId", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": {
          "200": { "description": "List of batch member enrichments" }
        }
      }
    },
    "/v1/enrichments/batches/{batchId}/approve": {
      "post": {
        "operationId": "approveBatch",
        "tags": ["Enrichment"],
        "summary": "Approve all enrichments in a batch",
        "parameters": [
          { "name": "batchId", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": {
          "200": { "description": "Batch approved" }
        }
      }
    },
    "/v1/enrichments/batches/{batchId}/export/excel": {
      "get": {
        "operationId": "exportBatchExcel",
        "tags": ["Enrichment"],
        "summary": "Export batch as Excel",
        "parameters": [
          { "name": "batchId", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": {
          "200": {
            "description": "Excel file download",
            "content": {
              "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": {
                "schema": { "type": "string", "format": "binary" }
              }
            }
          }
        }
      }
    },
    "/v1/enrichments/{id}/writeback": {
      "post": {
        "operationId": "executeWriteback",
        "tags": ["Enrichment"],
        "summary": "Execute CRM writeback",
        "description": "Push enriched data for a single enrichment to the connected CRM. The enrichment must be in approved status.",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "field_overrides": { "type": "object", "additionalProperties": true, "description": "Optional field-level overrides before writing" },
                  "create_if_missing": { "type": "boolean", "default": false, "description": "Create a new CRM contact if no match found" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Writeback completed successfully" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/enrichments/bulk-writeback": {
      "post": {
        "operationId": "bulkWriteback",
        "tags": ["Enrichment"],
        "summary": "Bulk writeback to CRM",
        "description": "Push enriched data for multiple enrichments to the connected CRM in a single operation.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["enrichment_ids"],
                "properties": {
                  "enrichment_ids": { "type": "array", "items": { "type": "integer" }, "description": "List of enrichment IDs to write back" },
                  "create_if_missing": { "type": "boolean", "default": false }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Bulk writeback results",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "succeeded": { "type": "integer" },
                    "failed": { "type": "integer" },
                    "errors": { "type": "array", "items": { "type": "object", "properties": { "enrichment_id": { "type": "integer" }, "error": { "type": "string" } } } }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/enrichments/batches/upload": {
      "post": {
        "operationId": "uploadBatchFile",
        "tags": ["Enrichment"],
        "summary": "Upload file for batch enrichment",
        "description": "Upload an Excel or CSV file containing contacts to enrich. Returns a preview of parsed rows and credit estimate.",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": ["file"],
                "properties": {
                  "file": { "type": "string", "format": "binary", "description": "Excel (.xlsx) or CSV file" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "File parsed with preview",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "upload_id": { "type": "string", "format": "uuid" },
                    "row_count": { "type": "integer" },
                    "columns_detected": { "type": "array", "items": { "type": "string" } },
                    "preview_rows": { "type": "array", "items": { "type": "object" } },
                    "estimated_credits": { "type": "integer" }
                  }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" }
        }
      }
    },
    "/v1/enrichments/batches/upload/confirm": {
      "post": {
        "operationId": "confirmUploadBatch",
        "tags": ["Enrichment"],
        "summary": "Confirm uploaded batch",
        "description": "Confirm a previously uploaded file and start batch enrichment processing.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["upload_id"],
                "properties": {
                  "upload_id": { "type": "string", "format": "uuid" },
                  "column_mapping": { "type": "object", "additionalProperties": { "type": "string" }, "description": "Map file columns to enrichment input fields" }
                }
              }
            }
          }
        },
        "responses": {
          "202": { "description": "Batch confirmed and processing started" },
          "400": { "$ref": "#/components/responses/BadRequest" }
        }
      }
    },
    "/v1/people-finder": {
      "post": {
        "operationId": "createPersonFinderJob",
        "tags": ["People Finder"],
        "summary": "Create person finder job",
        "description": "Start a new people-finder job to locate decision-makers at a target company by role. Searches multiple sources and optionally enriches and pushes to CRM.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/PersonFinderRequest" }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Job accepted for processing",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PersonFinderJob" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      },
      "get": {
        "operationId": "listPersonFinderJobs",
        "tags": ["People Finder"],
        "summary": "List person finder jobs",
        "description": "Return a paginated list of people-finder jobs for the current organization.",
        "parameters": [
          { "name": "status", "in": "query", "schema": { "type": "string", "enum": ["queued", "processing", "completed", "failed", "cancelled"] } },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 20 } },
          { "name": "offset", "in": "query", "schema": { "type": "integer", "default": 0 } }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of jobs",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": { "type": "array", "items": { "$ref": "#/components/schemas/PersonFinderJob" } },
                    "total": { "type": "integer" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/people-finder/{jobId}": {
      "get": {
        "operationId": "getPersonFinderJob",
        "tags": ["People Finder"],
        "summary": "Get job status and results",
        "description": "Retrieve the current status, progress, and results (if complete) for a people-finder job.",
        "parameters": [
          { "name": "jobId", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": {
          "200": {
            "description": "Job details with results",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PersonFinderJob" }
              }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      },
      "delete": {
        "operationId": "cancelPersonFinderJob",
        "tags": ["People Finder"],
        "summary": "Cancel job",
        "description": "Cancel a queued or in-progress people-finder job. Already-completed jobs cannot be cancelled.",
        "parameters": [
          { "name": "jobId", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": {
          "204": { "description": "Job cancelled" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/people-finder/{jobId}/stream": {
      "get": {
        "operationId": "streamPersonFinderJob",
        "tags": ["People Finder"],
        "summary": "SSE progress stream",
        "description": "Stream real-time progress updates for a people-finder job via Server-Sent Events.",
        "parameters": [
          { "name": "jobId", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": {
          "200": {
            "description": "Server-Sent Events stream",
            "content": {
              "text/event-stream": {
                "schema": { "type": "string" }
              }
            }
          }
        }
      }
    },
    "/v1/people-finder/list/preview": {
      "post": {
        "operationId": "previewPersonFinderList",
        "tags": ["People Finder"],
        "summary": "Preview HubSpot company list",
        "description": "Preview companies from a HubSpot list before submitting people-finder jobs. Returns company names, domains, and estimated credit cost.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["list_id"],
                "properties": {
                  "list_id": { "type": "string", "description": "HubSpot company list ID" },
                  "roles": { "type": "array", "items": { "type": "string" }, "description": "Roles to search for" },
                  "options": { "$ref": "#/components/schemas/PersonFinderOptions" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "List preview with companies and credit estimate",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "preview_id": { "type": "string", "format": "uuid" },
                    "companies": { "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string" }, "domain": { "type": "string" } } } },
                    "total_companies": { "type": "integer" },
                    "estimated_credits": { "type": "integer" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/people-finder/list/confirm": {
      "post": {
        "operationId": "confirmPersonFinderList",
        "tags": ["People Finder"],
        "summary": "Confirm and queue list jobs",
        "description": "Confirm a previously previewed HubSpot company list and queue people-finder jobs for all companies.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["preview_id"],
                "properties": {
                  "preview_id": { "type": "string", "format": "uuid" }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Jobs queued for all companies",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "jobs_created": { "type": "integer" },
                    "total_credits": { "type": "integer" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/people-finder/upload": {
      "post": {
        "operationId": "uploadPersonFinderFile",
        "tags": ["People Finder"],
        "summary": "Upload Excel file of companies",
        "description": "Upload an Excel file containing company names, domains, or LinkedIn URLs to run people-finder jobs against.",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": ["file"],
                "properties": {
                  "file": { "type": "string", "format": "binary", "description": "Excel (.xlsx) or CSV file with company data" },
                  "roles": { "type": "string", "description": "Comma-separated roles to search (can also be set at confirm)" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "File parsed with preview",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "upload_id": { "type": "string", "format": "uuid" },
                    "companies_detected": { "type": "integer" },
                    "preview": { "type": "array", "items": { "type": "object" } },
                    "estimated_credits": { "type": "integer" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/people-finder/upload/confirm": {
      "post": {
        "operationId": "confirmPersonFinderUpload",
        "tags": ["People Finder"],
        "summary": "Confirm uploaded companies",
        "description": "Confirm a previously uploaded file and queue people-finder jobs for the companies.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["upload_id"],
                "properties": {
                  "upload_id": { "type": "string", "format": "uuid" },
                  "roles": { "type": "array", "items": { "type": "string" } },
                  "options": { "$ref": "#/components/schemas/PersonFinderOptions" }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Jobs queued",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "jobs_created": { "type": "integer" },
                    "total_credits": { "type": "integer" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/campaigns/preview": {
      "post": {
        "operationId": "previewCampaign",
        "tags": ["Campaigns"],
        "summary": "Preview campaign",
        "description": "Preview a campaign before launching — returns estimated credit cost, target count, and validation warnings.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["name", "source"],
                "properties": {
                  "name": { "type": "string", "description": "Campaign name" },
                  "source": {
                    "type": "object",
                    "description": "Target source (CRM list, upload, or manual)",
                    "properties": {
                      "type": { "type": "string", "enum": ["hubspot_list", "upload", "manual"] },
                      "list_id": { "type": "string" },
                      "upload_id": { "type": "string", "format": "uuid" },
                      "companies": { "type": "array", "items": { "type": "object" } }
                    }
                  },
                  "roles": { "type": "array", "items": { "type": "string" } },
                  "options": {
                    "type": "object",
                    "properties": {
                      "enrich": { "type": "boolean", "default": true },
                      "auto_approve": { "type": "boolean", "default": false },
                      "create_in_crm": { "type": "boolean", "default": false },
                      "max_per_role": { "type": "integer", "default": 3 }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Campaign preview with estimates",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "preview_id": { "type": "string", "format": "uuid" },
                    "total_companies": { "type": "integer" },
                    "estimated_credits": { "type": "integer" },
                    "warnings": { "type": "array", "items": { "type": "string" } }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/campaigns/confirm": {
      "post": {
        "operationId": "confirmCampaign",
        "tags": ["Campaigns"],
        "summary": "Confirm and start campaign",
        "description": "Confirm a previewed campaign and begin processing. Credits are reserved at this point.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["preview_id"],
                "properties": {
                  "preview_id": { "type": "string", "format": "uuid" }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Campaign started",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Campaign" }
              }
            }
          }
        }
      }
    },
    "/v1/campaigns": {
      "get": {
        "operationId": "listCampaigns",
        "tags": ["Campaigns"],
        "summary": "List campaigns",
        "description": "Return a paginated list of campaigns for the current organization.",
        "parameters": [
          { "name": "status", "in": "query", "schema": { "type": "string", "enum": ["draft", "processing", "completed", "failed", "cancelled"] } },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 20 } },
          { "name": "offset", "in": "query", "schema": { "type": "integer", "default": 0 } }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of campaigns",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": { "type": "array", "items": { "$ref": "#/components/schemas/Campaign" } },
                    "total": { "type": "integer" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/campaigns/{id}": {
      "get": {
        "operationId": "getCampaign",
        "tags": ["Campaigns"],
        "summary": "Get campaign status",
        "description": "Retrieve current status, progress, and summary for a campaign.",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": {
          "200": {
            "description": "Campaign details",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Campaign" }
              }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      },
      "delete": {
        "operationId": "cancelCampaign",
        "tags": ["Campaigns"],
        "summary": "Cancel campaign",
        "description": "Cancel a running campaign. In-progress jobs will complete but no new jobs will be started.",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": {
          "204": { "description": "Campaign cancelled" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/campaigns/{id}/stream": {
      "get": {
        "operationId": "streamCampaign",
        "tags": ["Campaigns"],
        "summary": "SSE progress stream",
        "description": "Stream real-time progress updates for a campaign via Server-Sent Events.",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": {
          "200": {
            "description": "Server-Sent Events stream",
            "content": {
              "text/event-stream": {
                "schema": { "type": "string" }
              }
            }
          }
        }
      }
    },
    "/v1/campaigns/{id}/results": {
      "get": {
        "operationId": "getCampaignResults",
        "tags": ["Campaigns"],
        "summary": "Get campaign results with candidates",
        "description": "Retrieve all candidates found by the campaign, grouped by company.",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 50 } },
          { "name": "offset", "in": "query", "schema": { "type": "integer", "default": 0 } }
        ],
        "responses": {
          "200": {
            "description": "Campaign results",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": { "type": "array", "items": { "$ref": "#/components/schemas/PersonFinderCandidate" } },
                    "total": { "type": "integer" }
                  }
                }
              }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/campaigns/{id}/approve": {
      "post": {
        "operationId": "approveCampaignCandidates",
        "tags": ["Campaigns"],
        "summary": "Approve candidates",
        "description": "Approve selected candidates from a campaign for enrichment and CRM writeback.",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "candidate_ids": { "type": "array", "items": { "type": "string" }, "description": "Specific candidate IDs to approve. Omit to approve all." },
                  "enrich": { "type": "boolean", "default": true },
                  "create_in_crm": { "type": "boolean", "default": false }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Candidates approved" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/campaigns/{id}/writeback": {
      "post": {
        "operationId": "campaignWriteback",
        "tags": ["Campaigns"],
        "summary": "Trigger CRM writeback",
        "description": "Push all approved campaign candidates to the connected CRM.",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": {
          "200": {
            "description": "Writeback results",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "written": { "type": "integer" },
                    "skipped": { "type": "integer" },
                    "errors": { "type": "array", "items": { "type": "object" } }
                  }
                }
              }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/field-config": {
      "get": {
        "operationId": "listFieldConfigs",
        "tags": ["Field Configuration"],
        "summary": "List field configurations",
        "description": "Return all enrichment field configurations for the current organization, including enabled/disabled state, CRM mapping, and display order.",
        "responses": {
          "200": {
            "description": "List of field configurations",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": { "type": "array", "items": { "$ref": "#/components/schemas/FieldConfig" } }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/field-config/{fieldId}": {
      "put": {
        "operationId": "updateFieldConfig",
        "tags": ["Field Configuration"],
        "summary": "Update field config",
        "description": "Update a single field configuration — toggle enabled, change CRM mapping, set display order, etc.",
        "parameters": [
          { "name": "fieldId", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "enabled": { "type": "boolean" },
                  "required": { "type": "boolean" },
                  "crm_property": { "type": "string", "description": "CRM property to map this field to" },
                  "display_order": { "type": "integer" },
                  "label": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated field config",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/FieldConfig" }
              }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/field-config/reset": {
      "post": {
        "operationId": "resetFieldConfig",
        "tags": ["Field Configuration"],
        "summary": "Reset to defaults",
        "description": "Reset all field configurations to platform defaults. This cannot be undone.",
        "responses": {
          "200": {
            "description": "Field configs reset to defaults",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": { "type": "array", "items": { "$ref": "#/components/schemas/FieldConfig" } }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/enrichment-config": {
      "get": {
        "operationId": "getEnrichmentConfig",
        "tags": ["Enrichment Config"],
        "summary": "Get enrichment configuration",
        "description": "Return the global enrichment configuration for the current organization — source priority, auto-approval rules, writeback settings, etc.",
        "responses": {
          "200": {
            "description": "Enrichment configuration",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/EnrichmentConfiguration" }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "updateEnrichmentConfig",
        "tags": ["Enrichment Config"],
        "summary": "Update enrichment configuration",
        "description": "Update global enrichment settings. Partial updates are supported — only include the fields you want to change.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/EnrichmentConfiguration" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated configuration",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/EnrichmentConfiguration" }
              }
            }
          }
        }
      }
    },
    "/v1/enrichment-config/reset": {
      "post": {
        "operationId": "resetEnrichmentConfig",
        "tags": ["Enrichment Config"],
        "summary": "Reset to defaults",
        "description": "Reset enrichment configuration to platform defaults. This cannot be undone.",
        "responses": {
          "200": {
            "description": "Configuration reset to defaults",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/EnrichmentConfiguration" }
              }
            }
          }
        }
      }
    },
    "/v1/webhooks/subscriptions": {
      "get": {
        "operationId": "listWebhookSubscriptions",
        "tags": ["Webhooks"],
        "summary": "List webhook subscriptions",
        "description": "Return all webhook subscriptions for the current organization.",
        "responses": {
          "200": {
            "description": "List of subscriptions",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": { "type": "array", "items": { "$ref": "#/components/schemas/WebhookSubscription" } }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createWebhookSubscription",
        "tags": ["Webhooks"],
        "summary": "Create subscription",
        "description": "Create a new webhook subscription. The URL will receive POST requests with event payloads.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["url", "event_types"],
                "properties": {
                  "url": { "type": "string", "format": "uri", "description": "HTTPS endpoint to receive events" },
                  "event_types": { "type": "array", "items": { "type": "string" }, "description": "Event types to subscribe to" },
                  "secret": { "type": "string", "description": "Shared secret for HMAC signature verification" },
                  "is_active": { "type": "boolean", "default": true }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Subscription created",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/WebhookSubscription" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" }
        }
      }
    },
    "/v1/webhooks/subscriptions/{id}": {
      "get": {
        "operationId": "getWebhookSubscription",
        "tags": ["Webhooks"],
        "summary": "Get subscription",
        "description": "Retrieve a single webhook subscription by ID.",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": {
          "200": {
            "description": "Subscription details",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/WebhookSubscription" }
              }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      },
      "patch": {
        "operationId": "updateWebhookSubscription",
        "tags": ["Webhooks"],
        "summary": "Update subscription",
        "description": "Update an existing webhook subscription. Partial updates are supported.",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": { "type": "string", "format": "uri" },
                  "event_types": { "type": "array", "items": { "type": "string" } },
                  "secret": { "type": "string" },
                  "is_active": { "type": "boolean" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Subscription updated",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/WebhookSubscription" }
              }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      },
      "delete": {
        "operationId": "deleteWebhookSubscription",
        "tags": ["Webhooks"],
        "summary": "Delete subscription",
        "description": "Permanently delete a webhook subscription.",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": {
          "204": { "description": "Subscription deleted" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/webhooks/event-types": {
      "get": {
        "operationId": "listWebhookEventTypes",
        "tags": ["Webhooks"],
        "summary": "List available event types",
        "description": "Return all event types that can be subscribed to, with descriptions.",
        "responses": {
          "200": {
            "description": "Available event types",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "event_types": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "name": { "type": "string", "description": "Event type identifier (e.g. enrichment.completed)" },
                          "description": { "type": "string" },
                          "category": { "type": "string" }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/linkedin/accounts": {
      "get": {
        "operationId": "getLinkedInAccounts",
        "tags": ["LinkedIn"],
        "summary": "List connected LinkedIn accounts",
        "description": "Requires X-LinkedIn-Account header for account selection.",
        "responses": {
          "200": { "description": "List of connected LinkedIn accounts" }
        }
      }
    },
    "/v1/linkedin/profiles/{publicId}": {
      "get": {
        "operationId": "getLinkedInProfile",
        "tags": ["LinkedIn"],
        "summary": "Get LinkedIn profile",
        "description": "Requires X-LinkedIn-Account header.",
        "parameters": [
          { "name": "publicId", "in": "path", "required": true, "schema": { "type": "string" }, "description": "LinkedIn public identifier (vanity URL slug)" }
        ],
        "responses": {
          "200": { "description": "Full LinkedIn profile data" }
        }
      }
    },
    "/v1/linkedin/profiles/{publicId}/contact": {
      "get": {
        "operationId": "getLinkedInProfileContact",
        "tags": ["LinkedIn"],
        "summary": "Get profile contact info",
        "description": "Requires X-LinkedIn-Account header.",
        "parameters": [
          { "name": "publicId", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "Contact information (email, phone, etc.)" }
        }
      }
    },
    "/v1/linkedin/profiles/{publicId}/skills": {
      "get": {
        "operationId": "getLinkedInProfileSkills",
        "tags": ["LinkedIn"],
        "summary": "Get profile skills",
        "description": "Requires X-LinkedIn-Account header.",
        "parameters": [
          { "name": "publicId", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "List of skills with endorsement counts" }
        }
      }
    },
    "/v1/linkedin/profiles/{publicId}/network": {
      "get": {
        "operationId": "getLinkedInProfileNetwork",
        "tags": ["LinkedIn"],
        "summary": "Get profile network info",
        "description": "Requires X-LinkedIn-Account header.",
        "parameters": [
          { "name": "publicId", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "Network statistics (connections, followers)" }
        }
      }
    },
    "/v1/linkedin/profiles/{publicId}/posts": {
      "get": {
        "operationId": "getLinkedInProfilePosts",
        "tags": ["LinkedIn"],
        "summary": "Get recent posts by profile",
        "description": "Requires X-LinkedIn-Account header.",
        "parameters": [
          { "name": "publicId", "in": "path", "required": true, "schema": { "type": "string" } },
          { "name": "count", "in": "query", "schema": { "type": "integer", "default": 10 } }
        ],
        "responses": {
          "200": { "description": "List of recent posts with engagement metrics" }
        }
      }
    },
    "/v1/linkedin/profiles/{publicId}/history": {
      "post": {
        "operationId": "syncLinkedInPostHistory",
        "tags": ["LinkedIn"],
        "summary": "Sync full post history",
        "description": "Fetches and caches all historical posts for a profile. Requires X-LinkedIn-Account header.",
        "parameters": [
          { "name": "publicId", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "Sync completed with post count" }
        }
      },
      "get": {
        "operationId": "getLinkedInPostHistory",
        "tags": ["LinkedIn"],
        "summary": "Get cached post history",
        "description": "Returns previously synced post history from cache. Requires X-LinkedIn-Account header.",
        "parameters": [
          { "name": "publicId", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "Cached post history" }
        }
      }
    },
    "/v1/linkedin/profiles/{publicId}/diff": {
      "post": {
        "operationId": "diffLinkedInProfile",
        "tags": ["LinkedIn"],
        "summary": "Detect profile changes",
        "description": "Compares current profile against cached version to detect changes. Requires X-LinkedIn-Account header.",
        "parameters": [
          { "name": "publicId", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "Profile diff with changed fields" }
        }
      }
    },
    "/v1/linkedin/posts": {
      "post": {
        "operationId": "createLinkedInPost",
        "tags": ["LinkedIn"],
        "summary": "Create a LinkedIn post",
        "description": "Requires X-LinkedIn-Account header.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["text"],
                "properties": {
                  "text": { "type": "string" },
                  "content_type": { "type": "string" },
                  "visible_to_connections_only": { "type": "boolean", "default": false }
                }
              }
            }
          }
        },
        "responses": {
          "201": { "description": "Post created" }
        }
      }
    },
    "/v1/linkedin/media/upload": {
      "post": {
        "operationId": "uploadLinkedInMedia",
        "tags": ["LinkedIn"],
        "summary": "Upload media for a LinkedIn post",
        "description": "Requires X-LinkedIn-Account header.",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "file": { "type": "string", "format": "binary" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Media uploaded with asset URN" }
        }
      }
    },
    "/v1/linkedin/posts/{postUrn}": {
      "patch": {
        "operationId": "editLinkedInPost",
        "tags": ["LinkedIn"],
        "summary": "Edit a LinkedIn post",
        "description": "Requires X-LinkedIn-Account header.",
        "parameters": [
          { "name": "postUrn", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "text": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Post updated" }
        }
      },
      "delete": {
        "operationId": "deleteLinkedInPost",
        "tags": ["LinkedIn"],
        "summary": "Delete a LinkedIn post",
        "description": "Requires X-LinkedIn-Account header.",
        "parameters": [
          { "name": "postUrn", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "204": { "description": "Post deleted" }
        }
      }
    },
    "/v1/linkedin/posts/{postUrn}/comments": {
      "post": {
        "operationId": "commentOnLinkedInPost",
        "tags": ["LinkedIn"],
        "summary": "Comment on a post",
        "description": "Requires X-LinkedIn-Account header.",
        "parameters": [
          { "name": "postUrn", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["text"],
                "properties": {
                  "text": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": {
          "201": { "description": "Comment posted" }
        }
      },
      "get": {
        "operationId": "getLinkedInPostComments",
        "tags": ["LinkedIn"],
        "summary": "Get comments on a post",
        "description": "Requires X-LinkedIn-Account header.",
        "parameters": [
          { "name": "postUrn", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "List of comments" }
        }
      }
    },
    "/v1/linkedin/posts/{postUrn}/reactions": {
      "get": {
        "operationId": "getLinkedInPostReactions",
        "tags": ["LinkedIn"],
        "summary": "Get reactions on a post",
        "description": "Requires X-LinkedIn-Account header.",
        "parameters": [
          { "name": "postUrn", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "List of reactions" }
        }
      },
      "post": {
        "operationId": "reactToLinkedInPost",
        "tags": ["LinkedIn"],
        "summary": "React to a post",
        "description": "Requires X-LinkedIn-Account header.",
        "parameters": [
          { "name": "postUrn", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "reaction_type": { "type": "string", "enum": ["LIKE", "CELEBRATE", "SUPPORT", "LOVE", "INSIGHTFUL", "FUNNY"] }
                }
              }
            }
          }
        },
        "responses": {
          "201": { "description": "Reaction added" }
        }
      }
    },
    "/v1/linkedin/feed": {
      "get": {
        "operationId": "getLinkedInFeed",
        "tags": ["LinkedIn"],
        "summary": "Get home feed",
        "description": "Requires X-LinkedIn-Account header.",
        "parameters": [
          { "name": "count", "in": "query", "schema": { "type": "integer", "default": 10 } }
        ],
        "responses": {
          "200": { "description": "Feed posts" }
        }
      }
    },
    "/v1/linkedin/companies/{universalName}": {
      "get": {
        "operationId": "getLinkedInCompany",
        "tags": ["LinkedIn"],
        "summary": "Get company profile",
        "description": "Requires X-LinkedIn-Account header.",
        "parameters": [
          { "name": "universalName", "in": "path", "required": true, "schema": { "type": "string" }, "description": "Company vanity URL slug" }
        ],
        "responses": {
          "200": { "description": "Company profile data" }
        }
      }
    },
    "/v1/linkedin/companies/{universalName}/updates": {
      "get": {
        "operationId": "getLinkedInCompanyUpdates",
        "tags": ["LinkedIn"],
        "summary": "Get company updates",
        "description": "Requires X-LinkedIn-Account header.",
        "parameters": [
          { "name": "universalName", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "Company posts and updates" }
        }
      }
    },
    "/v1/linkedin/companies/{companyId}/employees": {
      "get": {
        "operationId": "getLinkedInCompanyEmployees",
        "tags": ["LinkedIn"],
        "summary": "Get company employees",
        "description": "Requires X-LinkedIn-Account header.",
        "parameters": [
          { "name": "companyId", "in": "path", "required": true, "schema": { "type": "string" }, "description": "Numeric company ID" }
        ],
        "responses": {
          "200": { "description": "List of company employees" }
        }
      }
    },
    "/v1/linkedin/companies/{universalName}/diff": {
      "post": {
        "operationId": "diffLinkedInCompany",
        "tags": ["LinkedIn"],
        "summary": "Detect company profile changes",
        "description": "Requires X-LinkedIn-Account header.",
        "parameters": [
          { "name": "universalName", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "Company profile diff" }
        }
      }
    },
    "/v1/linkedin/companies/{companyUrn}/follow": {
      "post": {
        "operationId": "followLinkedInCompany",
        "tags": ["LinkedIn"],
        "summary": "Follow a company",
        "description": "Requires X-LinkedIn-Account header.",
        "parameters": [
          { "name": "companyUrn", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "Company followed" }
        }
      },
      "delete": {
        "operationId": "unfollowLinkedInCompany",
        "tags": ["LinkedIn"],
        "summary": "Unfollow a company",
        "description": "Requires X-LinkedIn-Account header.",
        "parameters": [
          { "name": "companyUrn", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "Company unfollowed" }
        }
      }
    },
    "/v1/linkedin/search/people": {
      "post": {
        "operationId": "searchLinkedInPeople",
        "tags": ["LinkedIn"],
        "summary": "Search people on LinkedIn",
        "description": "Requires X-LinkedIn-Account header.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "keywords": { "type": "string" },
                  "filters": { "type": "object" },
                  "count": { "type": "integer", "default": 10 }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Search results with profile summaries" }
        }
      }
    },
    "/v1/linkedin/search/companies": {
      "post": {
        "operationId": "searchLinkedInCompanies",
        "tags": ["LinkedIn"],
        "summary": "Search companies on LinkedIn",
        "description": "Requires X-LinkedIn-Account header.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "keywords": { "type": "string" },
                  "filters": { "type": "object" },
                  "count": { "type": "integer", "default": 10 }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Company search results" }
        }
      }
    },
    "/v1/linkedin/search/jobs": {
      "post": {
        "operationId": "searchLinkedInJobs",
        "tags": ["LinkedIn"],
        "summary": "Search jobs on LinkedIn",
        "description": "Requires X-LinkedIn-Account header.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "keywords": { "type": "string" },
                  "filters": { "type": "object" },
                  "count": { "type": "integer", "default": 10 }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Job search results" }
        }
      }
    },
    "/v1/linkedin/search/posts": {
      "post": {
        "operationId": "searchLinkedInPosts",
        "tags": ["LinkedIn"],
        "summary": "Search posts on LinkedIn",
        "description": "Requires X-LinkedIn-Account header.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "keywords": { "type": "string" },
                  "filters": { "type": "object" },
                  "count": { "type": "integer", "default": 10 }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Post search results" }
        }
      }
    },
    "/v1/linkedin/jobs/{jobId}": {
      "get": {
        "operationId": "getLinkedInJobDetails",
        "tags": ["LinkedIn"],
        "summary": "Get job details",
        "description": "Requires X-LinkedIn-Account header.",
        "parameters": [
          { "name": "jobId", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "Job details" }
        }
      }
    },
    "/v1/linkedin/jobs/{jobId}/skills": {
      "get": {
        "operationId": "getLinkedInJobSkills",
        "tags": ["LinkedIn"],
        "summary": "Get skills required for a job",
        "description": "Requires X-LinkedIn-Account header.",
        "parameters": [
          { "name": "jobId", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "List of required skills" }
        }
      }
    },
    "/v1/linkedin/connections": {
      "get": {
        "operationId": "getLinkedInConnections",
        "tags": ["LinkedIn"],
        "summary": "List connections",
        "description": "Requires X-LinkedIn-Account header.",
        "parameters": [
          { "name": "skip", "in": "query", "schema": { "type": "integer", "default": 0 }, "description": "Number of records to skip" },
          { "name": "take", "in": "query", "schema": { "type": "integer", "default": 20 }, "description": "Number of records to return" }
        ],
        "responses": {
          "200": { "description": "Paginated list of connections" }
        }
      }
    },
    "/v1/linkedin/connections/requests": {
      "post": {
        "operationId": "sendLinkedInConnectionRequest",
        "tags": ["LinkedIn"],
        "summary": "Send a connection request",
        "description": "Requires X-LinkedIn-Account header.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "public_id": { "type": "string" },
                  "message": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": {
          "201": { "description": "Connection request sent" }
        }
      }
    },
    "/v1/linkedin/connections/{publicId}": {
      "delete": {
        "operationId": "removeLinkedInConnection",
        "tags": ["LinkedIn"],
        "summary": "Remove a connection",
        "description": "Requires X-LinkedIn-Account header.",
        "parameters": [
          { "name": "publicId", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "204": { "description": "Connection removed" }
        }
      }
    },
    "/v1/linkedin/connections/invitations": {
      "get": {
        "operationId": "getLinkedInInvitations",
        "tags": ["LinkedIn"],
        "summary": "Get pending invitations",
        "description": "Requires X-LinkedIn-Account header.",
        "responses": {
          "200": { "description": "List of pending connection invitations" }
        }
      }
    },
    "/v1/linkedin/connections/invitations/respond": {
      "post": {
        "operationId": "respondToLinkedInInvitation",
        "tags": ["LinkedIn"],
        "summary": "Respond to a connection invitation",
        "description": "Requires X-LinkedIn-Account header.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "invitation_id": { "type": "string" },
                  "action": { "type": "string", "enum": ["accept", "decline"] }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Invitation responded to" }
        }
      }
    },
    "/v1/linkedin/messages/conversations": {
      "get": {
        "operationId": "getLinkedInConversations",
        "tags": ["LinkedIn"],
        "summary": "List message conversations",
        "description": "Requires X-LinkedIn-Account header.",
        "responses": {
          "200": { "description": "List of conversations" }
        }
      },
      "post": {
        "operationId": "startLinkedInConversation",
        "tags": ["LinkedIn"],
        "summary": "Start a new conversation",
        "description": "Requires X-LinkedIn-Account header.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["profile_urns", "text"],
                "properties": {
                  "profile_urns": { "type": "array", "items": { "type": "string" } },
                  "text": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": {
          "201": { "description": "Conversation started" }
        }
      }
    },
    "/v1/linkedin/messages/conversations/{conversationUrn}": {
      "get": {
        "operationId": "getLinkedInConversationMessages",
        "tags": ["LinkedIn"],
        "summary": "Get messages in a conversation thread",
        "description": "Requires X-LinkedIn-Account header.",
        "parameters": [
          { "name": "conversationUrn", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "Thread messages" }
        }
      }
    },
    "/v1/linkedin/messages/conversations/{conversationUrn}/send": {
      "post": {
        "operationId": "sendLinkedInMessage",
        "tags": ["LinkedIn"],
        "summary": "Send a message in a conversation",
        "description": "Requires X-LinkedIn-Account header.",
        "parameters": [
          { "name": "conversationUrn", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["text"],
                "properties": {
                  "text": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": {
          "201": { "description": "Message sent" }
        }
      }
    },
    "/v1/linkedin/messages/person/{profileUrn}": {
      "get": {
        "operationId": "getLinkedInConversationWithPerson",
        "tags": ["LinkedIn"],
        "summary": "Get conversation with a specific person",
        "description": "Requires X-LinkedIn-Account header.",
        "parameters": [
          { "name": "profileUrn", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "Conversation messages with the specified person" }
        }
      }
    },
    "/v1/crm/config/integrations": {
      "get": {
        "operationId": "listCrmIntegrations",
        "tags": ["CRM"],
        "summary": "List CRM integrations",
        "parameters": [
          { "name": "activeOnly", "in": "query", "schema": { "type": "boolean" } }
        ],
        "responses": {
          "200": { "description": "List of CRM integrations" }
        }
      },
      "post": {
        "operationId": "createCrmIntegration",
        "tags": ["CRM"],
        "summary": "Create a CRM integration",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["integration_type", "display_name", "api_key"],
                "properties": {
                  "integration_type": { "type": "string" },
                  "display_name": { "type": "string" },
                  "api_key": { "type": "string" },
                  "portal_id": { "type": "string" },
                  "is_active": { "type": "boolean", "default": true }
                }
              }
            }
          }
        },
        "responses": {
          "201": { "description": "Integration created" }
        }
      }
    },
    "/v1/crm/config/integrations/{id}": {
      "get": {
        "operationId": "getCrmIntegration",
        "tags": ["CRM"],
        "summary": "Get a CRM integration",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": {
          "200": { "description": "Integration details" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      },
      "delete": {
        "operationId": "deleteCrmIntegration",
        "tags": ["CRM"],
        "summary": "Delete a CRM integration",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": {
          "204": { "description": "Integration deleted" }
        }
      }
    },
    "/v1/crm/config/integrations/test": {
      "post": {
        "operationId": "testCrmIntegration",
        "tags": ["CRM"],
        "summary": "Test CRM integration credentials",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["integration_type", "api_key"],
                "properties": {
                  "integration_type": { "type": "string" },
                  "api_key": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Test result with connectivity status" }
        }
      }
    },
    "/v1/crm/config/platforms/{platform}/health": {
      "get": {
        "operationId": "getCrmPlatformHealth",
        "tags": ["CRM"],
        "summary": "Check CRM platform health",
        "parameters": [
          { "name": "platform", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "Platform health status" }
        }
      }
    },
    "/v1/crm/config/platforms/{platform}/mappings": {
      "get": {
        "operationId": "getCrmFieldMappings",
        "tags": ["CRM"],
        "summary": "Get field mappings for a CRM platform",
        "parameters": [
          { "name": "platform", "in": "path", "required": true, "schema": { "type": "string" } },
          { "name": "entityType", "in": "query", "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "Field mapping configuration" }
        }
      }
    },
    "/v1/organizations/current": {
      "get": {
        "operationId": "getCurrentOrganization",
        "tags": ["Organization"],
        "summary": "Get current organization",
        "responses": {
          "200": { "description": "Current organization details" }
        }
      }
    },
    "/v1/organizations/signup": {
      "post": {
        "operationId": "signupOrganization",
        "tags": ["Organization"],
        "summary": "Provision organization for a new Clerk user",
        "description": "Public endpoint for freshly-signed-up Clerk users. Creates a new organization and default workspace, or returns the existing one if the Clerk user/org already maps to an internal organization. Requires a valid Clerk Bearer token in the Authorization header — no pre-existing backend organization is required.",
        "security": [
          { "BearerAuth": [] }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "organizationName": { "type": "string", "description": "Optional display name for the organization. Defaults to the authenticated user's name or email prefix." },
                  "name": { "type": "string", "description": "Optional display name for the owning user (fallback when the Clerk JWT does not carry a name claim)." },
                  "email": { "type": "string", "format": "email", "description": "Optional contact email (fallback when the Clerk JWT does not carry an email claim)." }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Organization already existed — returning the existing record (idempotent response)",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/SignupOrganizationResponse" }
              }
            }
          },
          "201": {
            "description": "Organization successfully created",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/SignupOrganizationResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/v1/api-keys": {
      "get": {
        "operationId": "listApiKeys",
        "tags": ["Organization"],
        "summary": "List API keys",
        "description": "List all API keys belonging to the authenticated organization. The secret key value is never returned after creation — only metadata.",
        "responses": {
          "200": {
            "description": "List of API keys",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "data": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/ApiKeySummary" }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createApiKey",
        "tags": ["Organization"],
        "summary": "Create API key",
        "description": "Generate a new API key. The plaintext `key` field is only returned once in this response — store it securely.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["name"],
                "properties": {
                  "name": { "type": "string", "description": "Human-readable label for the key" },
                  "description": { "type": "string", "description": "Optional long-form description" },
                  "environment": { "type": "string", "enum": ["test", "live"], "default": "live" },
                  "scopes": {
                    "type": "array",
                    "items": { "type": "string" },
                    "description": "Permission scopes (e.g. `enrichment:read`, `enrichment:write`). Defaults to read-only if omitted."
                  },
                  "expiresAt": { "type": "string", "format": "date-time", "description": "Optional expiry timestamp" },
                  "allowedIpAddresses": { "type": "string", "description": "Comma-separated CIDR allow-list" },
                  "allowedReferrers": { "type": "string", "description": "Comma-separated referrer allow-list" },
                  "rateLimitPerMinute": { "type": "integer", "description": "Override the default rate limit for this key" }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "API key created. The `key` field is shown only in this response.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/CreateApiKeyResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" }
        }
      }
    },
    "/v1/api-keys/{keyId}": {
      "get": {
        "operationId": "getApiKey",
        "tags": ["Organization"],
        "summary": "Get API key metadata",
        "parameters": [
          { "name": "keyId", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": {
            "description": "API key metadata",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ApiKeySummary" }
              }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      },
      "delete": {
        "operationId": "revokeApiKey",
        "tags": ["Organization"],
        "summary": "Revoke API key",
        "parameters": [
          { "name": "keyId", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "reason": { "type": "string", "description": "Audit log reason for the revocation" }
                }
              }
            }
          }
        },
        "responses": {
          "204": { "description": "API key revoked" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/api-keys/{keyId}/rotate": {
      "post": {
        "operationId": "rotateApiKey",
        "tags": ["Organization"],
        "summary": "Rotate API key",
        "description": "Revokes the existing key and creates a new one with the same name and scopes. The new plaintext `key` is returned once — store it securely.",
        "parameters": [
          { "name": "keyId", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": {
            "description": "API key rotated",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/CreateApiKeyResponse" }
              }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/organizations/workspaces": {
      "get": {
        "operationId": "listWorkspaces",
        "tags": ["Organization"],
        "summary": "List workspaces",
        "responses": {
          "200": { "description": "List of workspaces in the organization" }
        }
      },
      "post": {
        "operationId": "createWorkspace",
        "tags": ["Organization"],
        "summary": "Create a workspace",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["name"],
                "properties": {
                  "name": { "type": "string" },
                  "description": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": {
          "201": { "description": "Workspace created" }
        }
      }
    },
    "/health": {
      "get": {
        "operationId": "healthCheck",
        "tags": ["Health"],
        "summary": "Basic health check",
        "security": [],
        "responses": {
          "200": { "description": "Service is healthy" }
        }
      }
    },
    "/health/detailed": {
      "get": {
        "operationId": "detailedHealthCheck",
        "tags": ["Health"],
        "summary": "Detailed health check with dependency status",
        "security": [],
        "responses": {
          "200": { "description": "Detailed health status including database, Redis, and external service connectivity" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key"
      },
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "Clerk-issued JWT. Used for dashboard/portal requests and for the `/v1/organizations/signup` bootstrap endpoint."
      }
    },
    "schemas": {
      "EnrichmentInput": {
        "type": "object",
        "properties": {
          "name": { "type": "string" },
          "email": { "type": "string", "format": "email" },
          "firstName": { "type": "string" },
          "lastName": { "type": "string" },
          "company": { "type": "string" },
          "companyName": { "type": "string" },
          "firmName": { "type": "string" },
          "linkedInUrl": { "type": "string", "format": "uri" },
          "linkedInCompanyPage": { "type": "string", "format": "uri" },
          "domain": { "type": "string" },
          "website": { "type": "string", "format": "uri" },
          "crmId": { "type": "string" }
        }
      },
      "EnrichmentSummary": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "status": { "type": "string", "enum": ["queued", "processing", "completed", "approved", "writeback_pending", "synced", "failed", "cancelled", "partial_success"] },
          "type": { "type": "string" },
          "created_at": { "type": "string", "format": "date-time" }
        }
      },
      "EnrichmentResult": {
        "allOf": [
          { "$ref": "#/components/schemas/EnrichmentSummary" },
          {
            "type": "object",
            "properties": {
              "input": { "$ref": "#/components/schemas/EnrichmentInput" },
              "result_data": { "type": "object", "description": "Enriched data from all sources" },
              "sources": { "type": "array", "items": { "type": "string" } },
              "completed_at": { "type": "string", "format": "date-time" }
            }
          }
        ]
      },
      "PersonFinderOptions": {
        "type": "object",
        "properties": {
          "maxPerRole": { "type": "integer", "default": 3, "description": "Maximum candidates to return per role" },
          "enrich": { "type": "boolean", "default": false, "description": "Automatically enrich found candidates" },
          "createInCrm": { "type": "boolean", "default": false, "description": "Create found candidates in connected CRM" }
        }
      },
      "PersonFinderRequest": {
        "type": "object",
        "required": ["roles"],
        "properties": {
          "companyName": { "type": "string", "description": "Target company name" },
          "companyWebsite": { "type": "string", "format": "uri", "description": "Target company website URL" },
          "companyLinkedin": { "type": "string", "format": "uri", "description": "Target company LinkedIn page URL" },
          "roles": { "type": "array", "items": { "type": "string" }, "description": "Job roles to search for (e.g. VP Sales, CTO)" },
          "options": { "$ref": "#/components/schemas/PersonFinderOptions" }
        }
      },
      "PersonFinderCandidate": {
        "type": "object",
        "properties": {
          "name": { "type": "string" },
          "title": { "type": "string" },
          "matchedRole": { "type": "string", "description": "Which searched role this candidate matched" },
          "confidence": { "type": "number", "format": "float", "description": "Match confidence score (0-1)" },
          "email": { "type": "string", "format": "email" },
          "linkedinUrl": { "type": "string", "format": "uri" },
          "location": { "type": "string" },
          "sources": { "type": "array", "items": { "type": "string" }, "description": "Data sources that found this candidate" },
          "hubspotContactId": { "type": "string", "description": "HubSpot contact ID if created in CRM" },
          "enrichmentJobId": { "type": "integer", "description": "Enrichment job ID if enrich option was enabled" }
        }
      },
      "PersonFinderJob": {
        "type": "object",
        "properties": {
          "jobId": { "type": "string", "format": "uuid" },
          "status": { "type": "string", "enum": ["queued", "processing", "completed", "failed", "cancelled"] },
          "companyName": { "type": "string" },
          "roles": { "type": "array", "items": { "type": "string" } },
          "percentComplete": { "type": "integer", "minimum": 0, "maximum": 100 },
          "currentStep": { "type": "string", "description": "Human-readable description of the current processing step" },
          "createdAt": { "type": "string", "format": "date-time" },
          "completedAt": { "type": "string", "format": "date-time" },
          "result": {
            "type": "object",
            "properties": {
              "candidates": { "type": "array", "items": { "$ref": "#/components/schemas/PersonFinderCandidate" } },
              "rolesSearched": { "type": "integer" },
              "durationSeconds": { "type": "number" }
            }
          },
          "error": { "type": "string", "description": "Error message if status is failed" },
          "statusUrl": { "type": "string", "format": "uri", "description": "URL to poll for status updates" },
          "streamUrl": { "type": "string", "format": "uri", "description": "URL for SSE progress stream" }
        }
      },
      "Campaign": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "name": { "type": "string" },
          "status": { "type": "string", "enum": ["draft", "processing", "completed", "failed", "cancelled"] },
          "source_type": { "type": "string", "enum": ["hubspot_list", "upload", "manual"] },
          "total_companies": { "type": "integer" },
          "companies_completed": { "type": "integer" },
          "total_candidates_found": { "type": "integer" },
          "credits_used": { "type": "integer" },
          "created_at": { "type": "string", "format": "date-time" },
          "completed_at": { "type": "string", "format": "date-time" }
        }
      },
      "FieldConfig": {
        "type": "object",
        "properties": {
          "field_id": { "type": "string", "description": "Unique field identifier (e.g. email, title, company)" },
          "label": { "type": "string", "description": "Human-readable field label" },
          "category": { "type": "string", "description": "Field category (contact, company, social)" },
          "enabled": { "type": "boolean" },
          "required": { "type": "boolean" },
          "crm_property": { "type": "string", "description": "Mapped CRM property name" },
          "display_order": { "type": "integer" }
        }
      },
      "EnrichmentConfiguration": {
        "type": "object",
        "properties": {
          "source_priority": { "type": "array", "items": { "type": "string" }, "description": "Ordered list of enrichment source names" },
          "auto_approve": { "type": "boolean", "description": "Automatically approve enrichments that meet confidence threshold" },
          "auto_approve_threshold": { "type": "number", "format": "float", "description": "Minimum confidence for auto-approval (0-1)" },
          "auto_writeback": { "type": "boolean", "description": "Automatically write approved enrichments to CRM" },
          "dedup_strategy": { "type": "string", "enum": ["email", "name_company", "linkedin", "crm_id"], "description": "How to detect duplicate contacts" },
          "default_enrich_on_find": { "type": "boolean", "description": "Enrich candidates found via People Finder by default" }
        }
      },
      "WebhookSubscription": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "url": { "type": "string", "format": "uri" },
          "event_types": { "type": "array", "items": { "type": "string" } },
          "is_active": { "type": "boolean" },
          "created_at": { "type": "string", "format": "date-time" },
          "last_triggered_at": { "type": "string", "format": "date-time" },
          "failure_count": { "type": "integer", "description": "Consecutive delivery failures" }
        }
      },
      "ApiKeySummary": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "name": { "type": "string" },
          "description": { "type": "string" },
          "prefix": { "type": "string", "description": "Non-secret display prefix for the key (e.g. `abm_live_...`)" },
          "environment": { "type": "string", "enum": ["test", "live"] },
          "scopes": { "type": "array", "items": { "type": "string" } },
          "createdAt": { "type": "string", "format": "date-time" },
          "lastUsedAt": { "type": "string", "format": "date-time" },
          "expiresAt": { "type": "string", "format": "date-time" },
          "isActive": { "type": "boolean" },
          "revokedAt": { "type": "string", "format": "date-time" },
          "allowedIpAddresses": { "type": "string" },
          "allowedReferrers": { "type": "string" },
          "rateLimitPerMinute": { "type": "integer" }
        }
      },
      "CreateApiKeyResponse": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "key": { "type": "string", "description": "Plaintext API key — returned ONLY on creation/rotation. Store this securely; it cannot be retrieved again." },
          "name": { "type": "string" },
          "environment": { "type": "string", "enum": ["test", "live"] },
          "scopes": { "type": "array", "items": { "type": "string" } },
          "createdAt": { "type": "string", "format": "date-time" },
          "expiresAt": { "type": "string", "format": "date-time" },
          "warning": { "type": "string", "description": "Reminder that the plaintext key is only shown once" }
        }
      },
      "SignupOrganizationResponse": {
        "type": "object",
        "properties": {
          "organizationId": { "type": "string", "format": "uuid" },
          "organizationName": { "type": "string" },
          "organizationSlug": { "type": "string" },
          "clerkOrgId": { "type": "string", "description": "Clerk org ID (org_xxx) linked to this internal organization, if any" },
          "clerkUserId": { "type": "string", "description": "Clerk user ID that triggered signup" },
          "workspaceId": { "type": "string", "format": "uuid", "description": "Default workspace ID created alongside the organization" },
          "workspaceName": { "type": "string" },
          "created": { "type": "boolean", "description": "True when a new organization was provisioned by this request; false when an existing record was returned (idempotency)" }
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Invalid request parameters",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "error": { "type": "string" },
                "details": { "type": "object" }
              }
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Missing or invalid API key"
      },
      "NotFound": {
        "description": "Resource not found"
      }
    }
  }
}
