{"openapi":"3.0.0","info":{"title":"Contextra API","version":"1.0.0","description":"API for managing targets, products, pitches, and AI-powered sales assistance\n\n**OpenAPI Schema**: The OpenAPI schema is available at [https://api.contextra.tech/public/openapi.json](https://api.contextra.tech/public/openapi.json)\n","contact":{"name":"Contextra Team"}},"servers":[{"url":"https://api.contextra.tech","description":"Production server"}],"tags":[{"name":"Auth","description":"Public API endpoints for authentication"},{"name":"Targets","description":"Public API endpoints for target management"},{"name":"Pitches","description":"Public API endpoints for pitch management"}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"JWT token obtained from authentication endpoint"}},"schemas":{"Error":{"type":"object","properties":{"success":{"type":"boolean","example":false},"message":{"type":"string","example":"An error occurred"},"error":{"type":"object"}}},"PaginationInfo":{"type":"object","properties":{"page":{"type":"integer","example":1},"pageSize":{"type":"integer","example":10},"totalPages":{"type":"integer","example":5},"totalItems":{"type":"integer","example":47}}},"Target":{"type":"object","properties":{"id":{"type":"string","example":"abc123xyz"},"userId":{"type":"string","example":"user123"},"name":{"type":"string","example":"John Doe"},"company":{"type":"string","example":"Acme Corp"},"location":{"type":"string","example":"San Francisco, CA"},"linkedInUrl":{"type":"string","format":"uri","example":"https://linkedin.com/in/johndoe"},"email":{"type":"string","format":"email","example":"john.doe@acme.com"},"generatedData":{"type":"object","description":"AI-generated data about the target"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"Pitch":{"type":"object","properties":{"id":{"type":"string","example":"pitch123xyz"},"userId":{"type":"string","example":"user123"},"companyId":{"type":"string","example":"company123"},"productId":{"type":"string","example":"product123"},"targetId":{"type":"string","example":"target123"},"writingStyleId":{"type":"string","example":"style123"},"companyName":{"type":"string","example":"Acme Corp"},"productName":{"type":"string","example":"AI Analytics Platform"},"targetName":{"type":"string","example":"John Doe"},"targetEmail":{"type":"string","format":"email","example":"john.doe@acme.com"},"writingStyleTitle":{"type":"string","example":"Professional"},"type":{"type":"string","enum":["SYSTEM","USER"],"example":"USER"},"model":{"type":"string","enum":["chat-gpt","gemini"],"example":"chat-gpt"},"generatedData":{"type":"object","description":"AI-generated pitch data","properties":{"content":{"type":"string","description":"Generated pitch content"},"subject":{"type":"string","description":"Email subject line"},"title":{"type":"string","description":"Pitch title"},"status":{"type":"string","enum":["QUEUED","GENERATING","GENERATED","FAILED","NOT_GENERATED"],"example":"GENERATED"},"generatedAt":{"type":"string","format":"date-time"},"taskName":{"type":"string","description":"Cloud Task name for background processing"},"error":{"type":"string","description":"Error message if generation failed"}}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"Product":{"type":"object","properties":{"id":{"type":"string","example":"product123xyz"},"userId":{"type":"string","example":"user123"},"name":{"type":"string","example":"AI Analytics Platform"},"productUrl":{"type":"string","format":"uri","example":"https://example.com/product"},"generatedData":{"type":"object","description":"AI-generated data about the product","properties":{"status":{"type":"string","enum":["QUEUED","GENERATING","GENERATED","FAILED","NOT_GENERATED"],"example":"GENERATED"},"searchEngine":{"type":"string","enum":["brightdata","gemini"],"example":"brightdata"},"description":{"type":"string","example":"A comprehensive analytics platform powered by AI"},"keyFeatures":{"type":"array","items":{"type":"string"},"example":["Real-time analytics","AI-powered insights","Custom dashboards"]},"targetAudience":{"type":"array","items":{"type":"string"},"example":["Data analysts","Business intelligence teams","C-level executives"]},"pricing":{"type":"string","example":"Starting at $99/month"},"uniqueValueProposition":{"type":"array","items":{"type":"string"},"example":["10x faster insights","No coding required","Enterprise-grade security"]},"useCases":{"type":"array","items":{"type":"string"},"example":["Sales forecasting","Customer behavior analysis","Marketing ROI tracking"]},"generatedAt":{"type":"string","format":"date-time"},"generatingStartedAt":{"type":"string","format":"date-time"},"taskName":{"type":"string","description":"Cloud Task name for background processing"},"error":{"oneOf":[{"type":"string"},{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"statusCode":{"type":"integer"}}}],"description":"Error message or object if generation failed"}}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}}}},"paths":{"/public/v1/auth/token":{"post":{"summary":"Get authentication token","description":"Exchange email and password for a Firebase authentication token (custom token).\nThis token can be used in the `Authorization` header as `Bearer <token>` for subsequent requests.\n","operationId":"getPublicAuthToken","tags":["Auth"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email","password"],"properties":{"email":{"type":"string","format":"email","example":"user@example.com"},"password":{"type":"string","format":"password","example":"password123"},"returnSecureToken":{"type":"boolean","default":true,"description":"Whether to return the refresh token"}}}}}},"responses":{"200":{"description":"Successful authentication","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"idToken":{"type":"string","description":"The Firebase ID token"},"refreshToken":{"type":"string","description":"The refresh token"},"expiresIn":{"type":"string","description":"Token expiration time in seconds"},"localId":{"type":"string","description":"The user's unique ID"},"email":{"type":"string","description":"The user's email"},"displayName":{"type":"string","description":"The user's display name"},"kind":{"type":"string","description":"content type"},"registered":{"type":"boolean","description":"Whether the user is registered"}}}}}}}},"400":{"description":"Bad request - Missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized - Invalid email or password","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/public/v1/targets":{"post":{"summary":"Create a target","description":"Creates a new target for the authenticated user.\n\n**Required fields**: `name`, `company`, `location`, and at least one of `linkedInUrl` or `email`.\n\n**LinkedIn URL**: Must be a valid LinkedIn profile URL (e.g., https://linkedin.com/in/username).\n","operationId":"createPublicUserTarget","tags":["Targets"],"security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","company","location"],"properties":{"name":{"type":"string","description":"Full name of the target","example":"John Doe"},"company":{"type":"string","description":"Company name","example":"Acme Corp"},"location":{"type":"string","description":"Location of the target","example":"San Francisco, CA"},"linkedInUrl":{"type":"string","format":"uri","description":"LinkedIn profile URL (required if email is not provided)","example":"https://linkedin.com/in/johndoe"},"email":{"type":"string","format":"email","description":"Email address (required if linkedInUrl is not provided unless autoEnrich is true)","example":"john.doe@acme.com"},"autoEnrich":{"type":"boolean","description":"When true, resolve LinkedIn/email via Apollo using name and company before optional generation"},"processTarget":{"type":"boolean","description":"When true, queue DISC profile generation after create (requires LinkedIn or email, or autoEnrich)"}}},"examples":{"withLinkedIn":{"summary":"Create target with LinkedIn URL","value":{"name":"John Doe","company":"Acme Corp","location":"San Francisco, CA","linkedInUrl":"https://linkedin.com/in/johndoe","email":"john.doe@acme.com"}},"withEmail":{"summary":"Create target with email only","value":{"name":"Jane Smith","company":"Tech Inc","location":"New York, NY","email":"jane.smith@techinc.com"}}}}}},"responses":{"201":{"description":"Target created successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Target created successfully"},"data":{"$ref":"#/components/schemas/Target"}}}}}},"400":{"description":"Bad request - Validation errors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"missingFields":{"summary":"Missing required fields","value":{"success":false,"message":"Name, company, and location are required"}},"missingContact":{"summary":"Missing contact information","value":{"success":false,"message":"Either linkedInUrl or email must be provided"}},"invalidLinkedIn":{"summary":"Invalid LinkedIn URL","value":{"success":false,"message":"Invalid LinkedIn URL format"}},"duplicateName":{"summary":"Duplicate target name","value":{"success":false,"message":"A target with the name \"John Doe\" already exists"}}}}}},"401":{"description":"Unauthorized - Missing or invalid authentication token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden - User lacks required privilege","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"summary":"Get user targets","description":"Retrieves all targets for the authenticated user with optional pagination and sorting.\n\n**Pagination**: Use `page` and `pageSize` parameters to paginate results.\n**Sorting**: Use `sortBy` (field name) and `sortOrder` (asc/desc) to sort results.\n","operationId":"getPublicUserTargets","tags":["Targets"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":"integer","minimum":1,"default":1},"example":1},{"name":"pageSize","in":"query","description":"Number of items per page","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":10},"example":10},{"name":"sortBy","in":"query","description":"Field to sort by. Allowed values: name, createdAt","required":false,"schema":{"type":"string","enum":["name","createdAt"]},"example":"createdAt"},{"name":"sortOrder","in":"query","description":"Sort order","required":false,"schema":{"type":"string","enum":["asc","desc"],"default":"desc"},"example":"desc"}],"responses":{"200":{"description":"Successful response with paginated targets","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"targets":{"type":"array","items":{"$ref":"#/components/schemas/Target"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}}}}},"examples":{"success":{"summary":"Successful response","value":{"success":true,"data":{"targets":[{"id":"abc123","userId":"user123","name":"John Doe","company":"Acme Corp","location":"San Francisco, CA","linkedInUrl":"https://linkedin.com/in/johndoe","email":"john.doe@acme.com","createdAt":"2024-01-15T10:30:00Z","updatedAt":"2024-01-15T10:30:00Z"}],"pagination":{"page":1,"pageSize":10,"totalPages":5,"totalItems":47}}}}}}}},"400":{"description":"Bad request - Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalidPage":{"summary":"Invalid page number","value":{"success":false,"message":"Invalid page number. Must be >= 1"}},"invalidPageSize":{"summary":"Invalid page size","value":{"success":false,"message":"Invalid page size. Must be between 1 and 100"}},"invalidSortOrder":{"summary":"Invalid sort order","value":{"success":false,"message":"Invalid sort order. Must be \"asc\" or \"desc\""}}}}}},"401":{"description":"Unauthorized - Missing or invalid authentication token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"success":false,"message":"Unauthorized"}}}},"403":{"description":"Forbidden - User lacks required privilege","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"success":false,"message":"Insufficient privileges"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"success":false,"message":"Internal server error"}}}}}}},"/public/v1/targets/lookup":{"post":{"summary":"Lookup or create target with Apollo enrich","description":"Finds an existing target by exact name (and company when needed), or creates one.\nWhen LinkedIn URL and email are missing, resolves them via Apollo.io, then queues\nDISC profile generation (async). Poll `GET /public/v1/targets/{id}` until\n`generatedData.status` is `GENERATED`.\n\nRequires privilege `public:targets:lookup`.\n","operationId":"lookupPublicUserTarget","tags":["Targets"],"security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","company","location"],"properties":{"name":{"type":"string"},"company":{"type":"string"},"location":{"type":"string"},"processTarget":{"type":"boolean","default":true},"profileSource":{"type":"string","enum":["contextra","crystalknows"]},"webSearchEngine":{"type":"string","enum":["perplexity","gemini"]},"linkedinSource":{"type":"string","enum":["apify","brightdata"]},"forceSkipApolloCache":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Target found or created; generation may be queued","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Target"}}}}}},"400":{"description":"Missing required fields"},"422":{"description":"Apollo could not resolve contact identifiers"},"429":{"description":"Apollo rate limit"}}}},"/public/v1/targets/{id}":{"get":{"summary":"Get target by ID","description":"Retrieves a specific target by its ID for the authenticated user.","operationId":"getPublicUserTargetById","tags":["Targets"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Target ID","required":true,"schema":{"type":"string"},"example":"abc123xyz"}],"responses":{"200":{"description":"Successful response with target data","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Target"}}}}}},"400":{"description":"Bad request - Target ID required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"success":false,"message":"Target ID is required"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"success":false,"message":"Unauthorized"}}}},"404":{"description":"Target not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"success":false,"message":"Target not found"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"success":false,"message":"Internal server error"}}}}}},"put":{"summary":"Update a target (full update)","description":"Updates an existing target with new data. All fields should be provided.\nUse PATCH for partial updates.\n","operationId":"updatePublicUserTarget","tags":["Targets"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Target ID","required":true,"schema":{"type":"string"},"example":"abc123xyz"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Full name of the target","example":"John Doe Updated"},"company":{"type":"string","description":"Company name","example":"New Corp"},"location":{"type":"string","description":"Location of the target","example":"New York, NY"},"linkedInUrl":{"type":"string","format":"uri","description":"LinkedIn profile URL","example":"https://linkedin.com/in/johndoe"},"email":{"type":"string","format":"email","description":"Email address","example":"john.updated@newcorp.com"}}},"examples":{"fullUpdate":{"summary":"Full update of target","value":{"name":"John Doe Updated","company":"New Corp","location":"New York, NY","linkedInUrl":"https://linkedin.com/in/johndoe","email":"john.updated@newcorp.com"}}}}}},"responses":{"200":{"description":"Target updated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Target updated successfully"},"data":{"$ref":"#/components/schemas/Target"}}}}}},"400":{"description":"Bad request - Validation errors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden - User lacks required privilege","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Target not found or does not belong to user","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"success":false,"message":"Target not found"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"summary":"Update a target (partial update)","description":"Partially updates an existing target. Only provided fields will be updated.\n","operationId":"patchPublicUserTarget","tags":["Targets"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Target ID","required":true,"schema":{"type":"string"},"example":"abc123xyz"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Full name of the target","example":"John Doe"},"company":{"type":"string","description":"Company name","example":"Acme Corp"},"location":{"type":"string","description":"Location of the target","example":"San Francisco, CA"},"linkedInUrl":{"type":"string","format":"uri","description":"LinkedIn profile URL","example":"https://linkedin.com/in/johndoe"},"email":{"type":"string","format":"email","description":"Email address","example":"john.doe@acme.com"}}},"examples":{"updateEmail":{"summary":"Update only email","value":{"email":"newemail@example.com"}},"updateLocation":{"summary":"Update only location","value":{"location":"Remote"}},"updateMultiple":{"summary":"Update multiple fields","value":{"company":"Updated Corp","location":"Austin, TX","email":"updated@example.com"}}}}}},"responses":{"200":{"description":"Target updated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Target updated successfully"},"data":{"$ref":"#/components/schemas/Target"}}}}}},"400":{"description":"Bad request - Validation errors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden - User lacks required privilege","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Target not found or does not belong to user","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"success":false,"message":"Target not found"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"summary":"Delete a target","description":"Deletes an existing target. This action cannot be undone.\n","operationId":"deletePublicUserTarget","tags":["Targets"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Target ID","required":true,"schema":{"type":"string"},"example":"abc123xyz"}],"responses":{"200":{"description":"Target deleted successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Target deleted successfully"},"data":{"type":"object","properties":{"id":{"type":"string","description":"ID of the deleted target","example":"abc123xyz"}}}}}}}},"400":{"description":"Bad request - Target ID required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden - User lacks required privilege","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Target not found or does not belong to user","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"success":false,"message":"Target not found"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/public/v1/targets/batch-upload":{"post":{"summary":"Batch upload targets","description":"Upload multiple targets in a single request. Maximum 1,000 targets per upload.\n\nEach target requires: `name`, `company`, `location`, and `linkedInUrl`.\nThe `email` field is optional.\n\nLinkedIn URL must be a valid LinkedIn profile URL (e.g., https://linkedin.com/in/username).\n","operationId":"batchUploadPublicUserTargets","tags":["Targets"],"security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["targets"],"properties":{"targets":{"type":"array","description":"Array of targets to upload (max 1,000)","items":{"type":"object","required":["name","company","location","linkedInUrl"],"properties":{"name":{"type":"string","description":"Full name of the target","example":"John Doe"},"company":{"type":"string","description":"Company name","example":"Acme Corp"},"location":{"type":"string","description":"Location of the target","example":"San Francisco, CA"},"linkedInUrl":{"type":"string","format":"uri","description":"LinkedIn profile URL","example":"https://linkedin.com/in/johndoe"},"email":{"type":"string","format":"email","description":"Email address (optional)","example":"john.doe@acme.com"}}}},"webSearchEngine":{"type":"string","enum":["perplexity","gemini"],"description":"Web search engine to use for enrichment (optional, defaults to perplexity)","default":"perplexity","example":"perplexity"}}},"examples":{"basicUpload":{"summary":"Basic batch upload","value":{"targets":[{"name":"John Doe","company":"Acme Corp","location":"San Francisco, CA","linkedInUrl":"https://linkedin.com/in/johndoe","email":"john.doe@acme.com"},{"name":"Jane Smith","company":"Tech Inc","location":"New York, NY","linkedInUrl":"https://linkedin.com/in/janesmith"}]}},"withCacheOverride":{"summary":"Batch upload with cache override for specific targets","value":{"targets":[{"name":"John Doe","company":"Acme Corp","location":"San Francisco, CA","linkedInUrl":"https://linkedin.com/in/johndoe","email":"john.doe@acme.com","forceSkipCache":true},{"name":"Jane Smith","company":"Tech Inc","location":"New York, NY","linkedInUrl":"https://linkedin.com/in/janesmith","forceSkipCache":false}]}},"withWebSearchEngine":{"summary":"Batch upload with custom web search engine","value":{"targets":[{"name":"John Doe","company":"Acme Corp","location":"San Francisco, CA","linkedInUrl":"https://linkedin.com/in/johndoe","email":"john.doe@acme.com"},{"name":"Jane Smith","company":"Tech Inc","location":"New York, NY","linkedInUrl":"https://linkedin.com/in/janesmith","email":"jane.smith@techinc.com"}],"webSearchEngine":"perplexity"}},"completeExample":{"summary":"Complete example with all optional parameters","value":{"targets":[{"name":"John Doe","company":"Acme Corp","location":"San Francisco, CA","linkedInUrl":"https://linkedin.com/in/johndoe","email":"john.doe@acme.com","forceSkipCache":true},{"name":"Jane Smith","company":"Tech Inc","location":"New York, NY","linkedInUrl":"https://linkedin.com/in/janesmith","email":"jane.smith@techinc.com","forceSkipCache":false}],"webSearchEngine":"gemini"}}}}}},"responses":{"200":{"description":"Successful upload response (may include partial failures)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","description":"Summary message of the operation","example":"Batch upload completed: 2 targets created, 1 failed."},"data":{"type":"object","properties":{"successful":{"type":"array","description":"Array of successfully created targets","items":{"$ref":"#/components/schemas/Target"}},"failed":{"type":"array","description":"Array of targets that failed to create","items":{"type":"object","properties":{"index":{"type":"integer","description":"0-indexed position of the failed target in the request array","example":1},"reason":{"type":"string","description":"Reason for the failure","example":"A target with the name \"John Doe\" already exists"},"data":{"type":"object","description":"The target data that failed"}}}},"summary":{"type":"object","description":"Summary of the batch operation","properties":{"total":{"type":"integer","description":"Total number of targets in the request","example":4},"successful":{"type":"integer","description":"Number of targets successfully created","example":2},"failed":{"type":"integer","description":"Number of targets that failed","example":2}}}}}}},"examples":{"allSuccess":{"summary":"All targets created successfully","value":{"success":true,"message":"Batch upload completed successfully: 2 targets created. Background processing initiated.","data":{"successful":[{"id":"abc123","name":"John Doe","company":"Acme Corp","location":"San Francisco, CA","linkedInUrl":"https://linkedin.com/in/johndoe"},{"id":"def456","name":"Jane Smith","company":"Tech Inc","location":"New York, NY","linkedInUrl":"https://linkedin.com/in/janesmith"}],"failed":[],"summary":{"total":2,"successful":2,"failed":0}}}},"partialSuccess":{"summary":"Some targets failed (duplicates)","value":{"success":true,"message":"Batch upload completed: 2 targets created, 2 failed.","data":{"successful":[{"id":"abc123","name":"John Doe","company":"Acme Corp","location":"San Francisco, CA","linkedInUrl":"https://linkedin.com/in/johndoe"}],"failed":[{"index":1,"reason":"Duplicate name \"John Doe\" in batch","data":{"name":"John Doe","company":"Acme Corp","location":"San Francisco, CA","linkedInUrl":"https://linkedin.com/in/johndoe-duplicate"}},{"index":3,"reason":"A target with this LinkedIn URL already exists","data":{"name":"Jane Smith","company":"Tech Inc","location":"New York, NY","linkedInUrl":"https://linkedin.com/in/existing-url"}}],"summary":{"total":4,"successful":1,"failed":2}}}}}}}},"400":{"description":"Bad request - Validation errors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"emptyTargets":{"summary":"Empty targets array","value":{"success":false,"message":"Targets array is required and must not be empty"}},"tooManyRecords":{"summary":"Too many records","value":{"success":false,"message":"Request contains 1500 targets, but maximum 1000 records are allowed per upload"}}}}}},"401":{"description":"Unauthorized - Missing or invalid authentication token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"success":false,"message":"Unauthorized"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"success":false,"message":"Internal server error"}}}}}}},"/public/v1/targets/batch-delete":{"post":{"summary":"Batch delete targets","description":"Delete multiple targets in a single request.\n\nEach target must belong to the authenticated user. Targets that don't exist or don't belong to the user will be reported in the `failed` array with the reason for failure.\n\nThis operation processes each target individually - some may succeed while others fail.\n","operationId":"batchDeletePublicUserTargets","tags":["Targets"],"security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["ids"],"properties":{"ids":{"type":"array","description":"Array of target IDs to delete","items":{"type":"string"},"example":["abc123","def456","ghi789"]}}},"examples":{"basicDelete":{"summary":"Delete multiple targets","value":{"ids":["abc123","def456","ghi789"]}}}}}},"responses":{"200":{"description":"Batch delete completed (may include partial failures)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","description":"Summary message of the operation","example":"Batch delete completed: 2 deleted, 1 failed"},"data":{"type":"object","properties":{"deleted":{"type":"array","description":"Array of successfully deleted target IDs","items":{"type":"string"},"example":["abc123","def456"]},"failed":{"type":"array","description":"Array of targets that failed to delete","items":{"type":"object","properties":{"id":{"type":"string","description":"Target ID that failed to delete","example":"ghi789"},"reason":{"type":"string","description":"Reason for the failure","example":"Target not found or does not belong to user"}}}},"summary":{"type":"object","description":"Summary of the batch operation","properties":{"total":{"type":"integer","description":"Total number of target IDs in the request","example":3},"deleted":{"type":"integer","description":"Number of targets successfully deleted","example":2},"failed":{"type":"integer","description":"Number of targets that failed to delete","example":1}}}}}}},"examples":{"allSuccess":{"summary":"All targets deleted successfully","value":{"success":true,"message":"Batch delete completed: 3 deleted, 0 failed","data":{"deleted":["abc123","def456","ghi789"],"failed":[],"summary":{"total":3,"deleted":3,"failed":0}}}},"partialSuccess":{"summary":"Some targets failed to delete","value":{"success":true,"message":"Batch delete completed: 2 deleted, 1 failed","data":{"deleted":["abc123","def456"],"failed":[{"id":"ghi789","reason":"Target not found or does not belong to user"}],"summary":{"total":3,"deleted":2,"failed":1}}}}}}}},"400":{"description":"Bad request - Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"emptyArray":{"summary":"Empty IDs array","value":{"success":false,"message":"Target IDs array is required and must not be empty"}},"notArray":{"summary":"IDs is not an array","value":{"success":false,"message":"Target IDs array is required and must not be empty"}}}}}},"401":{"description":"Unauthorized - Missing or invalid authentication token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"success":false,"message":"Unauthorized"}}}},"403":{"description":"Forbidden - User lacks required privilege","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"success":false,"message":"User does not have the required privilege"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"success":false,"message":"Internal server error"}}}}}}},"/public/v1/targets/batch-generate":{"post":{"summary":"Batch generate target profile data","description":"Generate complete personality and professional profiles for multiple targets asynchronously using AI agents.\n\n**What gets generated:**\n- DISC personality profile (types, archetypes, D-I-S-C percentages)\n- Professional background (personal and work history)\n- Behavioral traits (8 behavioral characteristics)\n- Communication profile (style and preferences)\n- Values and motivations (personal and professional)\n\n**Processing:**\n- Maximum 1,000 targets per request\n- Each target requires either `linkedInUrl` OR `email`\n- Processing time: ~2 minutes per target\n- Targets are processed asynchronously via Google Cloud Tasks\n- Target state transitions: QUEUED → GENERATING → GENERATED/FAILED\n\n**Response:**\n- Returns immediately with queued targets and validation errors\n- Use `GET /public/v1/targets/:id` to monitor progress\n","operationId":"batchGeneratePublicUserTargets","tags":["Targets"],"security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["targetIds"],"properties":{"targetIds":{"type":"array","description":"Array of target IDs to generate profile data for (max 1,000)","items":{"type":"string"},"example":["abc123","def456","ghi789"],"maxItems":1000}}},"examples":{"basic":{"summary":"Generate profiles for multiple targets","value":{"targetIds":["target-id-1","target-id-2","target-id-3"]}},"single":{"summary":"Generate profile for a single target","value":{"targetIds":["target-id-1"]}}}}}},"responses":{"200":{"description":"Batch generation initiated (may include partial failures)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","description":"Summary message of the operation","example":"Batch generation initiated: 2 queued, 1 failed"},"data":{"type":"object","properties":{"queuedTargets":{"type":"array","description":"Targets successfully queued for generation","items":{"type":"object","properties":{"id":{"type":"string","description":"Target ID","example":"target-id-1"},"name":{"type":"string","description":"Target name","example":"John Doe"},"state":{"type":"string","description":"Current state (will be QUEUED)","example":"QUEUED"}}}},"invalidTargets":{"type":"array","description":"Targets that failed validation","items":{"type":"object","properties":{"id":{"type":"string","description":"Target ID that failed","example":"target-id-3"},"name":{"type":"string","description":"Target name (if found)","example":"Invalid User"},"reason":{"type":"string","description":"Reason for failure","example":"Target must have either linkedInUrl or email"}}}},"summary":{"type":"object","description":"Summary of the batch operation","properties":{"totalRequested":{"type":"integer","description":"Total number of target IDs in the request","example":3},"queued":{"type":"integer","description":"Number of targets successfully queued","example":2},"failed":{"type":"integer","description":"Number of targets that failed validation","example":1}}}}}}},"examples":{"allSuccess":{"summary":"All targets queued successfully","value":{"success":true,"message":"Batch generation initiated: 3 queued, 0 failed","data":{"queuedTargets":[{"id":"target-id-1","name":"John Doe","state":"QUEUED"},{"id":"target-id-2","name":"Jane Smith","state":"QUEUED"},{"id":"target-id-3","name":"Bob Johnson","state":"QUEUED"}],"invalidTargets":[],"summary":{"totalRequested":3,"queued":3,"failed":0}}}},"partialSuccess":{"summary":"Some targets failed validation","value":{"success":true,"message":"Batch generation initiated: 2 queued, 1 failed","data":{"queuedTargets":[{"id":"target-id-1","name":"John Doe","state":"QUEUED"},{"id":"target-id-2","name":"Jane Smith","state":"QUEUED"}],"invalidTargets":[{"id":"target-id-3","name":"Invalid User","reason":"Target must have either linkedInUrl or email"}],"summary":{"totalRequested":3,"queued":2,"failed":1}}}}}}}},"400":{"description":"Bad request - Invalid input or all targets failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"emptyArray":{"summary":"Empty target IDs array","value":{"success":false,"message":"Target IDs array is required and must not be empty","statusCode":400}},"tooManyTargets":{"summary":"Too many targets (over 1,000)","value":{"success":false,"message":"Maximum 1000 targets allowed per request","statusCode":400}},"allFailed":{"summary":"All targets failed validation","value":{"success":false,"message":"No valid targets to generate","statusCode":400,"data":{"invalidTargets":[{"id":"target-id-1","reason":"Target not found"},{"id":"target-id-2","reason":"Target must have either linkedInUrl or email"}]}}}}}}},"401":{"description":"Unauthorized - Missing or invalid authentication token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"success":false,"message":"Unauthorized","statusCode":401}}}},"403":{"description":"Forbidden - User lacks required privilege","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"success":false,"message":"User does not have the required privilege","statusCode":403}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"success":false,"message":"Internal server error","statusCode":500}}}}}}},"/public/v1/pitches":{"get":{"summary":"Get user pitches","description":"Retrieves all pitches for the authenticated user with optional pagination and sorting.\n\n**Pagination**: Use `page` and `pageSize` parameters to paginate results.\n**Sorting**: Use `sortBy` (field name) and `sortOrder` (asc/desc) to sort results.\n","operationId":"getPublicUserPitches","tags":["Pitches"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":"integer","minimum":1,"default":1},"example":1},{"name":"pageSize","in":"query","description":"Number of items per page","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":10},"example":10},{"name":"sortBy","in":"query","description":"Field to sort by. Allowed values: createdAt","required":false,"schema":{"type":"string","enum":["createdAt"]},"example":"createdAt"},{"name":"sortOrder","in":"query","description":"Sort order","required":false,"schema":{"type":"string","enum":["asc","desc"],"default":"desc"},"example":"desc"}],"responses":{"200":{"description":"Successful response with paginated pitches","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"pitches":{"type":"array","items":{"$ref":"#/components/schemas/Pitch"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}}}}},"examples":{"success":{"summary":"Successful response","value":{"success":true,"data":{"pitches":[{"id":"pitch123","userId":"user123","companyName":"Acme Corp","productName":"AI Analytics Platform","targetName":"John Doe","generatedData":{"status":"GENERATED","title":"John Doe - AI Analytics Platform"},"createdAt":"2024-01-15T10:30:00Z","updatedAt":"2024-01-15T10:30:00Z"}],"pagination":{"page":1,"pageSize":10,"totalPages":3,"totalItems":25}}}}}}}},"400":{"description":"Bad request - Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalidPage":{"summary":"Invalid page number","value":{"success":false,"message":"Invalid page number. Must be >= 1"}}}}}},"401":{"description":"Unauthorized - Missing or invalid authentication token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"success":false,"message":"Unauthorized"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"success":false,"message":"Internal server error"}}}}}},"post":{"summary":"Create a pitch","description":"Creates a new pitch for the authenticated user.\n\n**Required fields**: `targetId`, `productId`, and `companyId`.\n\nThe pitch will be created with status NOT_GENERATED. Use the generate endpoints to generate the pitch content.\n","operationId":"createPublicUserPitch","tags":["Pitches"],"security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["targetId","productId","companyId"],"properties":{"targetId":{"type":"string","description":"ID of the target for this pitch","example":"target-abc123"},"productId":{"type":"string","description":"ID of the product being pitched","example":"product-def456"},"companyId":{"type":"string","description":"ID of the company","example":"company-ghi789"}}},"examples":{"basic":{"summary":"Create a new pitch","value":{"targetId":"target-abc123","productId":"product-def456","companyId":"company-ghi789"}}}}}},"responses":{"201":{"description":"Pitch created successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Pitch created successfully"},"data":{"$ref":"#/components/schemas/Pitch"}}}}}},"400":{"description":"Bad request - Validation errors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"missingFields":{"summary":"Missing required fields","value":{"success":false,"message":"targetId, productId, and companyId are required"}},"invalidReferences":{"summary":"Invalid target/product/company references","value":{"success":false,"message":"Target, product, or company not found"}}}}}},"401":{"description":"Unauthorized - Missing or invalid authentication token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden - User lacks required privilege","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"summary":"Update a pitch","description":"Updates an existing pitch. Typically used to update the generated content (title, content).\n\nTo update the generated data, provide the `generatedData` object with the fields you want to update.\n","operationId":"updatePublicUserPitch","tags":["Pitches"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Pitch ID","required":true,"schema":{"type":"string"},"example":"pitch-123xyz"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"generatedData":{"type":"object","properties":{"title":{"type":"string","description":"Pitch title/subject line","example":"Introducing our new AI-powered solution"},"content":{"type":"string","description":"Pitch email content","example":"Hi John,\n\nI noticed your company is working on..."},"status":{"type":"string","enum":["NOT_GENERATED","QUEUED","GENERATING","GENERATED","FAILED"],"description":"Generation status","example":"GENERATED"}}}}},"examples":{"updateContent":{"summary":"Update pitch title and content","value":{"generatedData":{"title":"Updated pitch title","content":"Updated pitch content here...","status":"GENERATED"}}}}}}},"responses":{"200":{"description":"Pitch updated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Pitch updated successfully"},"data":{"$ref":"#/components/schemas/Pitch"}}}}}},"400":{"description":"Bad request - Validation errors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden - User lacks required privilege","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Pitch not found or does not belong to user","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"success":false,"message":"Pitch not found"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"summary":"Delete a pitch","description":"Deletes an existing pitch. This action cannot be undone.\n","operationId":"deletePublicUserPitch","tags":["Pitches"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Pitch ID","required":true,"schema":{"type":"string"},"example":"pitch-123xyz"}],"responses":{"200":{"description":"Pitch deleted successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Pitch deleted successfully"},"data":{"type":"object","properties":{"id":{"type":"string","description":"ID of the deleted pitch","example":"pitch-123xyz"}}}}}}}},"400":{"description":"Bad request - Pitch ID required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden - User lacks required privilege","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Pitch not found or does not belong to user","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"success":false,"message":"Pitch not found"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/public/v1/pitches/{id}":{"get":{"summary":"Get pitch by ID","description":"Retrieves a specific pitch by its ID for the authenticated user.","operationId":"getPublicUserPitchById","tags":["Pitches"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Pitch ID","required":true,"schema":{"type":"string"},"example":"pitch123xyz"}],"responses":{"200":{"description":"Successful response with pitch data","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Pitch"}}},"examples":{"success":{"summary":"Successful response","value":{"success":true,"data":{"id":"pitch123","userId":"user123","companyName":"Acme Corp","productName":"AI Analytics Platform","targetName":"John Doe","targetEmail":"john.doe@acme.com","generatedData":{"status":"GENERATED","title":"John Doe - AI Analytics Platform","content":"Hi John, I wanted to reach out...","subject":"AI Analytics Platform - Transform Your Data"},"createdAt":"2024-01-15T10:30:00Z","updatedAt":"2024-01-15T10:30:00Z"}}}}}}},"400":{"description":"Bad request - Pitch ID required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"success":false,"message":"Pitch ID is required"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"success":false,"message":"Unauthorized"}}}},"404":{"description":"Pitch not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"success":false,"message":"Pitch not found"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"success":false,"message":"Internal server error"}}}}}}},"/public/v1/pitches/batch-delete":{"post":{"summary":"Batch delete pitches","description":"Delete multiple pitches in a single request.\n\nEach pitch must belong to the authenticated user. Pitches that don't exist or don't belong to the user will be reported in the `failed` array with the reason for failure.\n\nThis operation processes each pitch individually - some may succeed while others fail.\n","operationId":"batchDeletePublicUserPitches","tags":["Pitches"],"security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["ids"],"properties":{"ids":{"type":"array","description":"Array of pitch IDs to delete","items":{"type":"string"},"example":["pitch-abc123","pitch-def456","pitch-ghi789"]}}},"examples":{"basicDelete":{"summary":"Delete multiple pitches","value":{"ids":["pitch-abc123","pitch-def456","pitch-ghi789"]}}}}}},"responses":{"200":{"description":"Batch delete completed (may include partial failures)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","description":"Summary message of the operation","example":"Batch delete completed: 2 deleted, 1 failed"},"data":{"type":"object","properties":{"deleted":{"type":"array","description":"Array of successfully deleted pitch IDs","items":{"type":"string"},"example":["pitch-abc123","pitch-def456"]},"failed":{"type":"array","description":"Array of pitches that failed to delete","items":{"type":"object","properties":{"id":{"type":"string","description":"Pitch ID that failed to delete","example":"pitch-ghi789"},"reason":{"type":"string","description":"Reason for the failure","example":"Pitch not found or does not belong to user"}}}},"summary":{"type":"object","description":"Summary of the batch operation","properties":{"total":{"type":"integer","description":"Total number of pitch IDs in the request","example":3},"deleted":{"type":"integer","description":"Number of pitches successfully deleted","example":2},"failed":{"type":"integer","description":"Number of pitches that failed to delete","example":1}}}}}}},"examples":{"allSuccess":{"summary":"All pitches deleted successfully","value":{"success":true,"message":"Batch delete completed: 3 deleted, 0 failed","data":{"deleted":["pitch-abc123","pitch-def456","pitch-ghi789"],"failed":[],"summary":{"total":3,"deleted":3,"failed":0}}}},"partialSuccess":{"summary":"Some pitches failed to delete","value":{"success":true,"message":"Batch delete completed: 2 deleted, 1 failed","data":{"deleted":["pitch-abc123","pitch-def456"],"failed":[{"id":"pitch-ghi789","reason":"Pitch not found or does not belong to user"}],"summary":{"total":3,"deleted":2,"failed":1}}}}}}}},"400":{"description":"Bad request - Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"emptyArray":{"summary":"Empty IDs array","value":{"success":false,"message":"Pitch IDs array is required and must not be empty"}},"notArray":{"summary":"IDs is not an array","value":{"success":false,"message":"Pitch IDs array is required and must not be empty"}}}}}},"401":{"description":"Unauthorized - Missing or invalid authentication token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"success":false,"message":"Unauthorized"}}}},"403":{"description":"Forbidden - User lacks required privilege","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"success":false,"message":"User does not have the required privilege"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"success":false,"message":"Internal server error"}}}}}}},"/public/v1/pitches/send-pitch-to-target":{"post":{"summary":"Send pitch to target","description":"Send a pitch email to its associated target.\n\nThe pitch must:\n- Exist and belong to the authenticated user\n- Have a `targetId` (be associated with a target)\n- Have a target with an email address\n- Have content in `generatedData.content`\n\nThe email will be queued for delivery via Google Cloud Tasks and sent using Mailgun.\n","operationId":"sendPublicPitchToTarget","tags":["Pitches"],"security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["pitchId"],"properties":{"pitchId":{"type":"string","description":"The ID of the pitch to send","example":"pitch-abc123"}}},"examples":{"sendPitch":{"summary":"Send a pitch","value":{"pitchId":"pitch-abc123"}}}}}},"responses":{"200":{"description":"Email queued successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Email queued for delivery"},"data":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Email queued successfully"},"email":{"type":"object","properties":{"id":{"type":"string","description":"Email ID","example":"email-xyz789"},"recipientEmail":{"type":"string","description":"Recipient email address","example":"target@example.com"},"recipientName":{"type":"string","description":"Recipient name","example":"John Doe"},"subject":{"type":"string","description":"Email subject","example":"Your personalized pitch"},"status":{"type":"string","description":"Email status","example":"QUEUED","enum":["QUEUED","SENT","FAILED"]},"emailType":{"type":"string","description":"Type of email","example":"PITCH"},"metadata":{"type":"object","description":"Email metadata","properties":{"pitchId":{"type":"string","example":"pitch-abc123"},"targetId":{"type":"string","example":"target-def456"},"companyId":{"type":"string","example":"company-ghi789"},"productId":{"type":"string","example":"product-jkl012"}}}}}}}}}}}},"400":{"description":"Bad request - Pitch validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"noPitchId":{"summary":"Missing pitch ID","value":{"success":false,"message":"Pitch ID is required"}},"noTarget":{"summary":"Pitch has no target","value":{"success":false,"message":"Pitch does not have a target associated"}},"noEmail":{"summary":"Target has no email","value":{"success":false,"message":"Target does not have an email address"}},"noContent":{"summary":"Pitch has no content","value":{"success":false,"message":"Pitch does not have content to send"}}}}}},"401":{"description":"Unauthorized - Missing or invalid authentication token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"success":false,"message":"Unauthorized"}}}},"403":{"description":"Forbidden - User lacks required privilege","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"success":false,"message":"User does not have the required privilege"}}}},"404":{"description":"Not found - Pitch or target not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"pitchNotFound":{"summary":"Pitch not found","value":{"success":false,"message":"Pitch not found or does not belong to user"}},"targetNotFound":{"summary":"Target not found","value":{"success":false,"message":"Target not found or does not belong to user"}}}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"success":false,"message":"Internal server error"}}}}}}},"/public/v1/pitches/batch-send-pitches":{"post":{"summary":"Batch send pitches to targets","description":"Send multiple pitch emails to their respective targets in a single request.\n\nEach pitch must:\n- Exist and belong to the authenticated user\n- Have a `targetId` (be associated with a target)\n- Have a target with an email address\n- Have content in `generatedData.content`\n\nThis operation processes each pitch individually - some may succeed while others fail.\nAll emails are queued for delivery via Google Cloud Tasks and sent using Mailgun.\n","operationId":"batchSendPublicPitchesToTargets","tags":["Pitches"],"security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["pitchIds"],"properties":{"pitchIds":{"type":"array","description":"Array of pitch IDs to send","items":{"type":"string"},"example":["pitch-abc123","pitch-def456","pitch-ghi789"]}}},"examples":{"batchSend":{"summary":"Send multiple pitches","value":{"pitchIds":["pitch-abc123","pitch-def456","pitch-ghi789"]}}}}}},"responses":{"200":{"description":"Batch send completed (may include partial failures)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","description":"Summary message of the operation","example":"Batch send completed: 2 successful, 1 failed"},"data":{"type":"object","properties":{"successful":{"type":"array","description":"Array of successfully sent pitches","items":{"type":"object","properties":{"pitchId":{"type":"string","description":"Pitch ID","example":"pitch-abc123"},"email":{"type":"object","properties":{"id":{"type":"string","description":"Email ID","example":"email-xyz789"},"recipientEmail":{"type":"string","description":"Recipient email address","example":"target@example.com"},"status":{"type":"string","description":"Email status","example":"QUEUED"}}}}}},"failed":{"type":"array","description":"Array of pitches that failed to send","items":{"type":"object","properties":{"pitchId":{"type":"string","description":"Pitch ID that failed","example":"pitch-ghi789"},"reason":{"type":"string","description":"Reason for the failure","example":"Target does not have an email address"}}}},"summary":{"type":"object","description":"Summary of the batch operation","properties":{"total":{"type":"integer","description":"Total number of pitch IDs in the request","example":3},"successful":{"type":"integer","description":"Number of pitches successfully sent","example":2},"failed":{"type":"integer","description":"Number of pitches that failed to send","example":1}}}}}}},"examples":{"allSuccess":{"summary":"All pitches sent successfully","value":{"success":true,"message":"Batch send completed: 3 successful, 0 failed","data":{"successful":[{"pitchId":"pitch-abc123","email":{"id":"email-xyz789","recipientEmail":"target1@example.com","status":"QUEUED"}},{"pitchId":"pitch-def456","email":{"id":"email-abc456","recipientEmail":"target2@example.com","status":"QUEUED"}},{"pitchId":"pitch-ghi789","email":{"id":"email-def123","recipientEmail":"target3@example.com","status":"QUEUED"}}],"failed":[],"summary":{"total":3,"successful":3,"failed":0}}}},"partialSuccess":{"summary":"Some pitches failed to send","value":{"success":true,"message":"Batch send completed: 2 successful, 1 failed","data":{"successful":[{"pitchId":"pitch-abc123","email":{"id":"email-xyz789","recipientEmail":"target1@example.com","status":"QUEUED"}},{"pitchId":"pitch-def456","email":{"id":"email-abc456","recipientEmail":"target2@example.com","status":"QUEUED"}}],"failed":[{"pitchId":"pitch-ghi789","reason":"Target does not have an email address"}],"summary":{"total":3,"successful":2,"failed":1}}}},"allFailed":{"summary":"All pitches failed to send","value":{"success":true,"message":"Batch send completed: 0 successful, 3 failed","data":{"successful":[],"failed":[{"pitchId":"pitch-abc123","reason":"Pitch not found"},{"pitchId":"pitch-def456","reason":"Target does not have an email address"},{"pitchId":"pitch-ghi789","reason":"Pitch does not have content to send"}],"summary":{"total":3,"successful":0,"failed":3}}}}}}}},"400":{"description":"Bad request - Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"emptyArray":{"summary":"Empty pitch IDs array","value":{"success":false,"message":"Pitch IDs are required"}},"notArray":{"summary":"Pitch IDs is not an array","value":{"success":false,"message":"Pitch IDs are required"}}}}}},"401":{"description":"Unauthorized - Missing or invalid authentication token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"success":false,"message":"Unauthorized"}}}},"403":{"description":"Forbidden - User lacks required privilege","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"success":false,"message":"User does not have the required privilege"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"success":false,"message":"Internal server error"}}}}}}},"/public/v1/pitches/batch-upload":{"post":{"summary":"Batch upload pitches","description":"Upload multiple pitches in a single request. Maximum 1,000 pitches per upload.\n\n**Uses the same fields as CSV upload**: `productName`, `targetName`, `pitchTitle`, `sendPitch`\n\nEach pitch requires: `productName` and `targetName`.\nOptional fields: `pitchTitle` and `sendPitch`.\n\nAll entity names must reference existing entities (products, targets) that belong to the authenticated user.\n\nThe API will:\n- Resolve product and target names to IDs\n- Check for duplicate product+target combinations\n- Automatically generate pitch content in the background\n- Optionally send pitches after generation (if `sendPitch: true` or `sendAllPitches: true`)\n","operationId":"batchUploadPublicUserPitches","tags":["Pitches"],"security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["pitches"],"properties":{"pitches":{"type":"array","description":"Array of pitches to upload (max 1,000)","items":{"type":"object","required":["productName","targetName"],"properties":{"productName":{"type":"string","description":"Name of the product to pitch (will be resolved to product ID)","example":"AI Analytics Platform"},"targetName":{"type":"string","description":"Name of the target person (will be resolved to target ID)","example":"John Doe"},"pitchTitle":{"type":"string","description":"Custom title for the pitch (optional, auto-generated if not provided)","example":"Q1 Partnership Proposal"},"sendPitch":{"type":"boolean","description":"Whether to send this pitch after generation (optional)","default":false,"example":true}}}},"model":{"type":"string","enum":["chat-gpt","gemini"],"description":"AI model to use for generation (optional, defaults to chat-gpt)","default":"chat-gpt","example":"chat-gpt"},"sendAllPitches":{"type":"boolean","description":"Override per-pitch sendPitch setting and send all pitches after generation (optional)","default":false,"example":false}}},"examples":{"basicUpload":{"summary":"Basic batch upload with automatic generation","value":{"pitches":[{"productName":"AI Analytics Platform","targetName":"John Doe","pitchTitle":"Q1 Sales Pitch"},{"productName":"Cloud Migration Services","targetName":"Jane Smith"}]}},"withCustomModel":{"summary":"Batch upload with specific AI model","value":{"pitches":[{"productName":"AI Analytics Platform","targetName":"John Doe","pitchTitle":"Partnership Proposal"},{"productName":"Cloud Migration Services","targetName":"Jane Smith","pitchTitle":"Q4 Sales Pitch"}],"model":"gemini"}},"withSendPitch":{"summary":"Batch upload with automatic sending","value":{"pitches":[{"productName":"AI Analytics Platform","targetName":"John Doe","pitchTitle":"Q1 Sales Pitch","sendPitch":true},{"productName":"Cloud Migration Services","targetName":"Jane Smith","pitchTitle":"Partnership Proposal","sendPitch":false}],"sendAllPitches":false}},"withModelAndSendAll":{"summary":"Batch upload with custom model and send all pitches","value":{"pitches":[{"productName":"AI Analytics Platform","targetName":"John Doe","pitchTitle":"Q1 Sales Pitch"},{"productName":"Cloud Migration Services","targetName":"Jane Smith","pitchTitle":"Partnership Proposal"}],"model":"gemini","sendAllPitches":true}}}}}},"responses":{"200":{"description":"Successful upload response (may include partial failures)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","description":"Summary message of the operation","example":"Batch upload completed successfully: 2 pitches created. Background generation initiated."},"data":{"type":"object","properties":{"successful":{"type":"array","description":"Array of successfully created pitches","items":{"$ref":"#/components/schemas/Pitch"}},"failed":{"type":"array","description":"Array of pitches that failed to create","items":{"type":"object","properties":{"index":{"type":"integer","description":"0-indexed position of the failed pitch in the request array","example":1},"reason":{"type":"string","description":"Reason for the failure","example":"Product \"Unknown Product\" not found"},"data":{"type":"object","description":"The pitch data that failed"}}}},"summary":{"type":"object","description":"Summary of the batch operation","properties":{"total":{"type":"integer","description":"Total number of pitches in the request","example":4},"successful":{"type":"integer","description":"Number of pitches successfully created","example":3},"failed":{"type":"integer","description":"Number of pitches that failed","example":1}}}}}}},"examples":{"allSuccess":{"summary":"All pitches created successfully","value":{"success":true,"message":"Batch upload completed successfully: 2 pitches created. Background generation initiated.","data":{"successful":[{"id":"pitch123","userId":"user123","companyName":"Acme Corp","productName":"AI Analytics Platform","targetName":"John Doe","generatedData":{"status":"QUEUED","title":"John Doe - AI Analytics Platform"}},{"id":"pitch456","userId":"user123","companyName":"Acme Corp","productName":"Cloud Migration Services","targetName":"Jane Smith","generatedData":{"status":"QUEUED","title":"Jane Smith - Cloud Migration Services"}}],"failed":[],"summary":{"total":2,"successful":2,"failed":0}}}},"partialSuccess":{"summary":"Some pitches failed (entity not found)","value":{"success":true,"message":"Batch upload completed: 2 pitches created, 2 failed.","data":{"successful":[{"id":"pitch123","companyName":"Acme Corp","productName":"AI Analytics Platform","targetName":"John Doe","generatedData":{"status":"NOT_GENERATED","title":"John Doe - AI Analytics Platform"}}],"failed":[{"index":1,"reason":"Product \"Unknown Product\" not found","data":{"productName":"Unknown Product","targetName":"John Doe"}},{"index":2,"reason":"Target \"Unknown Person\" not found","data":{"productName":"AI Analytics Platform","targetName":"Unknown Person"}}],"summary":{"total":3,"successful":1,"failed":2}}}},"duplicateCombination":{"summary":"Duplicate product+target combination","value":{"success":true,"message":"Batch upload completed: 1 pitches created, 1 failed.","data":{"successful":[{"id":"pitch123","companyName":"Acme Corp","productName":"AI Analytics Platform","targetName":"John Doe"}],"failed":[{"index":1,"reason":"Pitch with this product and target combination already exists","data":{"productName":"AI Analytics Platform","targetName":"John Doe"}}],"summary":{"total":2,"successful":1,"failed":1}}}}}}}},"400":{"description":"Bad request - Validation errors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"emptyPitches":{"summary":"Empty pitches array","value":{"success":false,"message":"Pitches array is required and must not be empty"}},"tooManyRecords":{"summary":"Too many records","value":{"success":false,"message":"Request contains 1500 pitches, but maximum 1000 records are allowed per upload"}},"missingRequired":{"summary":"Missing required fields","value":{"success":false,"message":"Request contains validation errors. Please fix the errors and try again.","data":{"errors":[{"index":0,"reason":"Missing or empty required fields: targetName","data":{"productName":"AI Analytics Platform"}}],"summary":{"total":1,"valid":0,"invalid":1}}}}}}}},"401":{"description":"Unauthorized - Missing or invalid authentication token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"success":false,"message":"Unauthorized"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"success":false,"message":"Internal server error"}}}}}}},"/public/v1/products":{"post":{"summary":"Create a product","description":"Creates a new product for the authenticated user.\n\n**Required fields**: `name` and `productUrl`.\n","operationId":"createPublicUserProduct","tags":["Products"],"security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","productUrl"],"properties":{"name":{"type":"string","description":"Product name","example":"AI Analytics Platform"},"productUrl":{"type":"string","format":"uri","description":"Product website URL","example":"https://example.com/product"}}},"examples":{"basic":{"summary":"Create a new product","value":{"name":"AI Analytics Platform","productUrl":"https://example.com/product"}}}}}},"responses":{"201":{"description":"Product created successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Product created successfully"},"data":{"$ref":"#/components/schemas/Product"}}}}}},"400":{"description":"Bad request - Validation errors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized - Missing or invalid authentication token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden - User lacks required privilege","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"summary":"Get user products","description":"Retrieves all products for the authenticated user with optional pagination and sorting.\n\n**Pagination**: Use `page` and `pageSize` parameters to paginate results.\n**Sorting**: Use `sortBy` (field name) and `sortOrder` (asc/desc) to sort results.\n","operationId":"getPublicUserProducts","tags":["Products"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":"integer","minimum":1,"default":1}},{"name":"pageSize","in":"query","description":"Number of items per page","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":10}},{"name":"sortBy","in":"query","description":"Field to sort by","required":false,"schema":{"type":"string","enum":["createdAt","name"]}},{"name":"sortOrder","in":"query","description":"Sort order","required":false,"schema":{"type":"string","enum":["asc","desc"],"default":"desc"}}],"responses":{"200":{"description":"Successful response with paginated products","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"products":{"type":"array","items":{"$ref":"#/components/schemas/Product"}},"pagination":{"$ref":"#/components/schemas/PaginationInfo"}}}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/public/v1/products/{id}":{"get":{"summary":"Get product by ID","description":"Retrieves a specific product by its ID for the authenticated user.","operationId":"getPublicUserProductById","tags":["Products"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Product ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successful response with product data","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Product"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Product not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"summary":"Update a product","description":"Updates an existing product with new data.\n","operationId":"updatePublicUserProduct","tags":["Products"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Product ID","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Product name","example":"AI Analytics Platform Updated"},"productUrl":{"type":"string","format":"uri","description":"Product website URL","example":"https://example.com/product"}}},"examples":{"update":{"summary":"Update product details","value":{"name":"AI Analytics Platform Updated","productUrl":"https://example.com/product"}}}}}},"responses":{"200":{"description":"Product updated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Product updated successfully"},"data":{"$ref":"#/components/schemas/Product"}}}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Product not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"summary":"Delete a product","description":"Deletes an existing product. This action cannot be undone.\n","operationId":"deletePublicUserProduct","tags":["Products"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","description":"Product ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Product deleted successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Product deleted successfully"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Product not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}