{"openapi":"3.0.3","info":{"title":"Parlay API","description":"Partner-facing API for Parlay pitch scoring, rep intelligence, and coaching. See API.md for the full spec.","version":"0.1.0"},"components":{"securitySchemes":{"ApiKeyAuth":{"type":"http","scheme":"bearer","bearerFormat":"API Key (pk_sandbox_* or pk_live_*)"}},"schemas":{}},"paths":{"/v1/health":{"get":{"summary":"Health check (public)","tags":["Health"],"description":"Liveness probe. Returns ok / degraded / down + uptime.","responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["ok","degraded","down"]},"uptime_seconds":{"type":"number"}},"required":["status","uptime_seconds"],"additionalProperties":false}}}}}}},"/v1/version":{"get":{"summary":"API version + build info","tags":["Health"],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"api_version":{"type":"string"},"release":{"type":"string"},"node_env":{"type":"string"},"commit":{"type":"string","nullable":true},"built_at":{"type":"string","nullable":true}},"required":["api_version","release","node_env","commit","built_at"],"additionalProperties":false}}}}}}},"/v1/status":{"get":{"summary":"Public service status","tags":["Health"],"description":"Per-provider health and queue depth. Safe for public status pages.","responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["operational","degraded","maintenance","outage"]},"uptime_seconds":{"type":"number"},"providers":{"type":"object","properties":{"deepgram":{"type":"string","enum":["operational","degraded","outage","not_configured"]},"gemini":{"type":"string","enum":["operational","degraded","outage","not_configured"]},"supabase":{"type":"string","enum":["operational","degraded","outage","not_configured"]},"pubsub":{"type":"string","enum":["operational","degraded","outage","not_configured"]}},"required":["deepgram","gemini","supabase","pubsub"],"additionalProperties":false},"queue_depth":{"type":"object","properties":{"analyses":{"type":"number"},"webhooks":{"type":"number"},"exports":{"type":"number"}},"required":["analyses","webhooks","exports"],"additionalProperties":false}},"required":["status","uptime_seconds","providers","queue_depth"],"additionalProperties":false}}}}}}},"/v1/keys/me":{"get":{"summary":"Introspect the current API key","tags":["Keys"],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"api_key_id":{"type":"string","format":"uuid"},"partner_id":{"type":"string","format":"uuid"},"key_id":{"type":"string"},"key_prefix":{"type":"string"},"environment":{"type":"string","enum":["sandbox","production"]},"live":{"type":"boolean"},"scopes":{"type":"array","items":{"type":"string"}},"created_at":{"type":"string"},"last_used_at":{"type":"string","nullable":true},"revoke_after":{"type":"string","nullable":true}},"required":["api_key_id","partner_id","key_id","key_prefix","environment","live","scopes","created_at","last_used_at","revoke_after"],"additionalProperties":false}}}}}}},"/v1/keys/rotate":{"post":{"summary":"Rotate the current key","tags":["Keys"],"description":"Mints a new key with identical scopes + environment. Current key stays valid for 24h, then auto-revokes.","responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"new_key_id":{"type":"string"},"key":{"type":"string"},"key_prefix":{"type":"string"},"environment":{"type":"string","enum":["sandbox","production"]},"live":{"type":"boolean"},"old_key_revokes_at":{"type":"string"},"warning":{"type":"string"}},"required":["new_key_id","key","key_prefix","environment","live","old_key_revokes_at","warning"],"additionalProperties":false}}}}}}},"/v1/keys/revoke":{"post":{"summary":"Revoke the current key immediately","tags":["Keys"],"responses":{"200":{"description":"Default Response"}}}},"/v1/analyses":{"post":{"summary":"Submit a recording for analysis","tags":["Analyses"],"description":"Returns 202 with a job handle. Completion is delivered via webhook (see /v1/webhooks) or via polling GET /v1/analyses/:id. In sandbox, use `mock://perfect-pitch` etc. for deterministic results.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"org_id":{"type":"string","minLength":1,"maxLength":256,"pattern":"^[A-Za-z0-9._:-]+$","description":"Opaque identifier from your system. Treat this like a foreign key — pass a stable ID (Salesforce User ID, HubSpot Owner ID, your internal UUID), not a display name. Display names (\"alex\", \"brooke\") work but cause real problems: collisions between people with the same first name, history loss on rename, no clean migration if employment changes. Once you set this for a rep or org, treat it as immutable. Charset: [A-Za-z0-9._:-], 1-256 chars."},"rep_id":{"type":"string","minLength":1,"maxLength":256,"pattern":"^[A-Za-z0-9._:-]+$","description":"Opaque identifier from your system. Treat this like a foreign key — pass a stable ID (Salesforce User ID, HubSpot Owner ID, your internal UUID), not a display name. Display names (\"alex\", \"brooke\") work but cause real problems: collisions between people with the same first name, history loss on rename, no clean migration if employment changes. Once you set this for a rep or org, treat it as immutable. Charset: [A-Za-z0-9._:-], 1-256 chars."},"recording_url":{"type":"string","format":"uri"},"transcript_url":{"type":"string","format":"uri"},"callback_url":{"type":"string","format":"uri"},"options":{"type":"object","properties":{"persona_id":{"type":"integer"},"methodology_id":{"type":"integer"},"playbook_id":{"type":"string","format":"uuid"},"scoring_profile_id":{"type":"string","format":"uuid"},"prompt_overrides":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string"},"content":{"type":"string"}},"required":["title","content"],"additionalProperties":false}},"language":{"type":"string"},"skip_diarization":{"type":"boolean"},"recording_type":{"type":"string"},"environment":{"type":"string"},"sales_motion":{"type":"string"}},"additionalProperties":true},"metadata":{"type":"object","additionalProperties":{}}},"required":["org_id","rep_id"],"additionalProperties":false}}}},"responses":{"202":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["queued","processing","completed","failed","cancelled"]},"created_at":{"type":"string"}},"required":["id","status","created_at"],"additionalProperties":false}}}}}},"get":{"summary":"List analyses","tags":["Analyses"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"org_id","required":false},{"schema":{"type":"string"},"in":"query","name":"rep_id","required":false},{"schema":{"type":"string","enum":["queued","processing","completed","failed","cancelled"]},"in":"query","name":"status","required":false},{"schema":{"type":"string","format":"date-time"},"in":"query","name":"from","required":false},{"schema":{"type":"string","format":"date-time"},"in":"query","name":"to","required":false},{"schema":{"type":"integer","minimum":0,"maximum":100},"in":"query","name":"min_score","required":false},{"schema":{"type":"integer","minimum":1,"maximum":100},"in":"query","name":"limit","required":false},{"schema":{"type":"string"},"in":"query","name":"cursor","required":false}],"responses":{"200":{"description":"Default Response"}}}},"/v1/analyses/{id}":{"get":{"summary":"Fetch an analysis","tags":["Analyses"],"description":"Returns the full analysis row. When `status === \"completed\"` the `analysis` field is populated with the canonical six-pillar shape (clarity / influence / objection / discovery / delivery / close), each pillar exposed as a flat `*_score` field plus `feedback_v5.<pillar>.{positive, negative}` and `action_plan_v5`. KPIs (`questions_asked`, `filler_word_count`, `words_per_minute`) are flat at the top of `analysis`. Mock fixtures emit the same shape so a partner can decode `mock://*` and real audio with one decoder.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["queued","processing","completed","failed","cancelled"]},"recording_url":{"type":"string","nullable":true},"transcript_url":{"type":"string","nullable":true},"callback_url":{"type":"string","nullable":true},"options":{"type":"object","additionalProperties":{}},"metadata":{"type":"object","additionalProperties":{}},"transcript":{"type":"object","properties":{"text":{"type":"string"},"utterances":{"type":"array","items":{"type":"object","properties":{"speaker":{"anyOf":[{"type":"string"},{"type":"number"}]},"start":{"type":"number"},"end":{"type":"number"},"transcript":{"type":"string"},"text":{"type":"string"}},"required":["start","end"],"additionalProperties":true}},"words":{"type":"array","items":{"type":"object","additionalProperties":{}}},"word_count":{"type":"integer","minimum":0},"duration_seconds":{"type":"number","minimum":0},"overall_sentiment":{"type":"string","nullable":true},"sentiment_score":{"type":"number","nullable":true}},"additionalProperties":true,"nullable":true},"analysis":{"type":"object","properties":{"prospect_name":{"type":"string","nullable":true},"recording_title":{"type":"string"},"double_down":{"type":"string"},"ai_summary":{"type":"string"},"ai_summary_v5":{"type":"string"},"questions_asked":{"type":"integer","minimum":0},"filler_word_count":{"type":"integer","minimum":0},"words_per_minute":{"type":"number","minimum":0},"overall_score":{"type":"integer","minimum":0,"maximum":100},"clarity_score":{"type":"integer","minimum":0,"maximum":100},"influence_score":{"type":"integer","minimum":0,"maximum":100},"objection_score":{"type":"integer","minimum":0,"maximum":100},"discovery_score":{"type":"integer","minimum":0,"maximum":100},"delivery_score":{"type":"integer","minimum":0,"maximum":100},"close_score":{"type":"integer","minimum":0,"maximum":100},"feedback_v5":{"type":"object","properties":{"clarity":{"type":"object","properties":{"positive":{"type":"string"},"negative":{"type":"string"}},"required":["positive","negative"],"additionalProperties":false},"influence":{"type":"object","properties":{"positive":{"type":"string"},"negative":{"type":"string"}},"required":["positive","negative"],"additionalProperties":false},"objection":{"type":"object","properties":{"positive":{"type":"string"},"negative":{"type":"string"}},"required":["positive","negative"],"additionalProperties":false},"discovery":{"type":"object","properties":{"positive":{"type":"string"},"negative":{"type":"string"}},"required":["positive","negative"],"additionalProperties":false},"delivery":{"type":"object","properties":{"positive":{"type":"string"},"negative":{"type":"string"}},"required":["positive","negative"],"additionalProperties":false},"close":{"type":"object","properties":{"positive":{"type":"string"},"negative":{"type":"string"}},"required":["positive","negative"],"additionalProperties":false}},"required":["clarity","influence","objection","discovery","delivery","close"],"additionalProperties":false},"action_plan_v5":{"type":"object","properties":{"double_down_implementation":{"type":"string"},"general_communication_improvement":{"type":"string"},"quoted_principle":{"type":"string"}},"required":["double_down_implementation","general_communication_improvement","quoted_principle"],"additionalProperties":false},"organization_prompt_summary":{"type":"string","nullable":true},"organization_feedback":{"type":"string","nullable":true},"master_prompt_id":{"type":"string","nullable":true},"master_prompt_version":{"type":"string"},"persona_snapshot":{"type":"object","additionalProperties":{},"nullable":true},"synthesis_snapshot":{"type":"object","additionalProperties":{},"nullable":true}},"required":["prospect_name","recording_title","double_down","ai_summary","ai_summary_v5","questions_asked","filler_word_count","words_per_minute","overall_score","clarity_score","influence_score","objection_score","discovery_score","delivery_score","close_score","feedback_v5","action_plan_v5","organization_prompt_summary","organization_feedback","master_prompt_id","master_prompt_version","persona_snapshot","synthesis_snapshot"],"additionalProperties":false,"nullable":true},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"object","additionalProperties":{}}},"required":["code","message"],"additionalProperties":false,"nullable":true},"duration_seconds":{"type":"integer","nullable":true},"cost_usd_cents":{"anyOf":[{"type":"number"},{"type":"string"}],"nullable":true},"created_at":{"type":"string"},"started_at":{"type":"string","nullable":true},"completed_at":{"type":"string","nullable":true},"partner_org_id":{"type":"string","format":"uuid","nullable":true},"partner_rep_id":{"type":"string","format":"uuid","nullable":true},"parent_session_id":{"type":"string","format":"uuid","nullable":true}},"required":["id","status","recording_url","transcript_url","callback_url","options","metadata","transcript","analysis","error","duration_seconds","cost_usd_cents","created_at","started_at","completed_at","partner_org_id","partner_rep_id","parent_session_id"],"additionalProperties":false}}}}}},"delete":{"summary":"Soft-delete an analysis","tags":["Analyses"],"parameters":[{"schema":{"type":"string","enum":["archive","purge"],"default":"archive"},"in":"query","name":"mode","required":false},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/v1/analyses/{id}/rescore":{"post":{"summary":"Rescore an analysis (Phase 1.B)","tags":["Analyses"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/v1/all-day-sessions":{"post":{"summary":"Submit a long-form recording for boundary detection + per-segment analysis","tags":["All-day sessions"],"description":"Upload one HTTPS URL of a multi-hour recording. The server detects conversation boundaries (single-shot Gemini), then auto-analyzes each high-confidence segment with the V5 master prompt. Each segment becomes a first-class Analysis row with `parent_session_id` set, queryable via the existing `/v1/analyses` surface.\n\n**Audio storage:** we never re-host the file. The response contains `start_seconds`/`end_seconds` offsets — your UI uses HTTP Range requests on your original URL to play any segment. See `/guides/all-day-sessions` for the full pattern.\n\n**Pricing:** ~$0.30 per hour of audio for detection (Deepgram + Gemini boundary call) plus ~$0.30 per detected segment for V5 analysis.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"recording_url":{"type":"string","format":"uri","description":"Publicly reachable HTTPS URL of the long-form audio. Pre-signed S3/GCS URLs are perfect. Audio stays on partner storage — we never re-host the file. Mutually exclusive with file_key."},"file_key":{"type":"string","minLength":1,"maxLength":512,"description":"GCS key returned from POST /v1/admin/partners/:id/uploads/signed-url after a browser-direct PUT. The server resolves this to a 1-hour signed read URL internally. Mutually exclusive with recording_url."},"org_id":{"type":"string","minLength":1,"maxLength":256,"pattern":"^[A-Za-z0-9._:-]+$","description":"Partner-supplied org id this session belongs to."},"rep_id":{"type":"string","minLength":1,"maxLength":256,"pattern":"^[A-Za-z0-9._:-]+$","description":"Partner-supplied rep id. Required — every segment analysis is scoped to this rep."},"options":{"type":"object","properties":{"auto_analyze":{"type":"boolean","description":"Default true. When true, every detected segment with confidence >= min_confidence is auto-submitted for V5 analysis. When false, segments are detected only — partner triggers each analysis manually via POST /v1/all-day-sessions/:id/segments/:seg_id/analyze."},"min_confidence":{"type":"number","minimum":0,"maximum":1,"description":"Default 0.8. Segments at or above this confidence auto-analyze. Segments below 0.5 are skipped entirely. Segments in between go to status='needs_review' and the partner can decide whether to analyze them."},"callback_url":{"type":"string","format":"uri","description":"Optional ad-hoc webhook URL for THIS session only. Receives all_day_session.detected/completed/failed events. Use registered webhooks (POST /v1/webhooks) for the standard partner-wide subscription."},"language":{"type":"string","description":"ISO language code for Deepgram. Auto-detect if omitted."},"skip_diarization":{"type":"boolean","description":"Default false. Diarization is required for boundary detection — only set to true if you know the audio is single-speaker monologue."},"playbook_id":{"type":"string","format":"uuid","description":"Override the active playbook for every segment in this session."},"prompt_overrides":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string"},"content":{"type":"string"}},"required":["title","content"],"additionalProperties":false},"description":"Inline custom prompts applied to every segment in this session."}},"additionalProperties":true},"metadata":{"type":"object","additionalProperties":{},"description":"Free-form key/value bag for partner bookkeeping. Not interpreted by Parlay."}},"required":["org_id","rep_id"],"additionalProperties":false}}}},"responses":{"202":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["queued","transcribing","detecting","analyzing","completed","failed"]},"created_at":{"type":"string"}},"required":["id","status","created_at"],"additionalProperties":false}}}}}},"get":{"summary":"List all-day sessions for the partner","tags":["All-day sessions"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"org_id","required":false},{"schema":{"type":"string"},"in":"query","name":"rep_id","required":false},{"schema":{"type":"string","enum":["queued","transcribing","detecting","analyzing","completed","failed"]},"in":"query","name":"status","required":false},{"schema":{"type":"integer","minimum":1,"maximum":100},"in":"query","name":"limit","required":false},{"schema":{"type":"string"},"in":"query","name":"cursor","required":false}],"responses":{"200":{"description":"Default Response"}}}},"/v1/all-day-sessions/{id}":{"get":{"summary":"Fetch a session with all detected segments","tags":["All-day sessions"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["queued","transcribing","detecting","analyzing","completed","failed"]},"recording_url":{"type":"string"},"duration_seconds":{"type":"integer","nullable":true},"segments_detected":{"type":"integer","minimum":0},"segments_analyzed":{"type":"integer","minimum":0},"segments_pending_review":{"type":"integer","minimum":0},"segments_skipped":{"type":"integer","minimum":0},"segments":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"start_seconds":{"type":"number"},"end_seconds":{"type":"number"},"confidence":{"type":"number","nullable":true},"customer_name":{"type":"string","nullable":true},"is_sales_conversation":{"type":"boolean","nullable":true},"detected_outcome":{"type":"string","nullable":true},"summary":{"type":"string","nullable":true},"status":{"type":"string","enum":["detected","analyzing","analyzed","needs_review","skipped","failed"]},"analysis_id":{"type":"string","format":"uuid","nullable":true},"analysis_url":{"type":"string","nullable":true},"playback":{"type":"object","properties":{"recording_url":{"type":"string","description":"Echo of the parent session's recording_url so a single segment is self-contained."},"start_seconds":{"type":"number"},"end_seconds":{"type":"number"},"browser_seek_js":{"type":"string","description":"JavaScript snippet that seeks an HTML5 <audio>/<video> element to the segment and stops at end_seconds. Modern browsers issue HTTP Range requests automatically — only the relevant byte range downloads."},"ffmpeg_extract":{"type":"string","description":"Shell command to extract the segment to a local file via ffmpeg with -c copy (no re-encoding, instant). Useful for offline export, archival, or feeding the slice into another tool."}},"required":["recording_url","start_seconds","end_seconds","browser_seek_js","ffmpeg_extract"],"additionalProperties":false,"description":"Ready-to-paste recipes for playing or extracting this segment from the original recording. We never re-host audio — these are convenience snippets that operate on your URL."},"created_at":{"type":"string"},"analyzed_at":{"type":"string","nullable":true}},"required":["id","start_seconds","end_seconds","confidence","customer_name","is_sales_conversation","detected_outcome","summary","status","analysis_id","analysis_url","playback","created_at","analyzed_at"],"additionalProperties":false}},"options":{"type":"object","additionalProperties":{}},"metadata":{"type":"object","additionalProperties":{}},"callback_url":{"type":"string","nullable":true},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"object","additionalProperties":{}}},"required":["code","message"],"additionalProperties":false,"nullable":true},"created_at":{"type":"string"},"started_at":{"type":"string","nullable":true},"completed_at":{"type":"string","nullable":true},"partner_org_id":{"type":"string","format":"uuid","nullable":true},"partner_rep_id":{"type":"string","format":"uuid","nullable":true}},"required":["id","status","recording_url","duration_seconds","segments_detected","segments_analyzed","segments_pending_review","segments_skipped","segments","options","metadata","callback_url","error","created_at","started_at","completed_at","partner_org_id","partner_rep_id"],"additionalProperties":false}}}}}},"delete":{"summary":"Archive a session (soft delete — child analyses remain queryable)","tags":["All-day sessions"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/v1/all-day-sessions/{id}/segments/{segment_id}/analyze":{"post":{"summary":"Manually trigger V5 analysis on a detected segment","tags":["All-day sessions"],"description":"Only needed when the session was submitted with `options.auto_analyze=false` or when a segment was sent to needs_review (confidence between 0.5 and the min_confidence threshold). The analysis runs asynchronously; poll GET /v1/analyses/:id once the segment row reports `status=analyzed`.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"segment_id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/v1/webhooks":{"post":{"summary":"Register a webhook","tags":["Webhooks"],"description":"signing_secret is returned exactly once — store it immediately.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri","maxLength":2048},"enabled_events":{"type":"array","items":{"type":"string","enum":["analysis.queued","analysis.completed","analysis.failed","persona.assigned","methodology.assigned","profile.synthesized","playbook.draft.completed","playbook.published","insights.generated","batch.completed","batch.item.completed","batch.item.failed","export.ready","all_day_session.processing_started","all_day_session.detected","all_day_session.completed","all_day_session.failed","webhook.test"]},"minItems":1},"name":{"type":"string","maxLength":120,"nullable":true},"description":{"type":"string","maxLength":2000,"nullable":true}},"required":["url","enabled_events"],"additionalProperties":false}}}},"responses":{"200":{"description":"Default Response"}}},"get":{"summary":"List webhooks","tags":["Webhooks"],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":100},"in":"query","name":"limit","required":false},{"schema":{"type":"string"},"in":"query","name":"cursor","required":false}],"responses":{"200":{"description":"Default Response"}}}},"/v1/webhooks/{id}":{"get":{"summary":"Fetch a webhook","tags":["Webhooks"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}},"patch":{"summary":"Update a webhook","tags":["Webhooks"],"description":"Pass rotate_secret=true to regenerate the signing secret — it is returned in the response exactly once.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri","maxLength":2048},"enabled_events":{"type":"array","items":{"type":"string","enum":["analysis.queued","analysis.completed","analysis.failed","persona.assigned","methodology.assigned","profile.synthesized","playbook.draft.completed","playbook.published","insights.generated","batch.completed","batch.item.completed","batch.item.failed","export.ready","all_day_session.processing_started","all_day_session.detected","all_day_session.completed","all_day_session.failed","webhook.test"]},"minItems":1},"paused":{"type":"boolean"},"name":{"type":"string","maxLength":120,"nullable":true},"description":{"type":"string","maxLength":2000,"nullable":true},"rotate_secret":{"type":"boolean"}},"additionalProperties":false}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Delete a webhook (soft)","tags":["Webhooks"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/v1/webhooks/{id}/test":{"post":{"summary":"Send a webhook.test event to the registered URL","tags":["Webhooks"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/v1/webhooks/{id}/deliveries":{"get":{"summary":"List deliveries for a webhook","tags":["Webhooks"],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":100},"in":"query","name":"limit","required":false},{"schema":{"type":"string"},"in":"query","name":"cursor","required":false},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/v1/webhooks/{id}/deliveries/{delivery_id}":{"get":{"summary":"Fetch a single delivery with payload + response","tags":["Webhooks"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"delivery_id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/v1/webhooks/{id}/deliveries/{delivery_id}/replay":{"post":{"summary":"Replay a delivery (Phase 9)","tags":["Webhooks"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"delivery_id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/v1/orgs":{"post":{"summary":"Create (or upsert) an org","tags":["Orgs"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"org_id":{"type":"string","minLength":1,"maxLength":256,"pattern":"^[A-Za-z0-9._:-]+$","description":"Opaque identifier from your system. Treat this like a foreign key — pass a stable ID (Salesforce User ID, HubSpot Owner ID, your internal UUID), not a display name. Display names (\"alex\", \"brooke\") work but cause real problems: collisions between people with the same first name, history loss on rename, no clean migration if employment changes. Once you set this for a rep or org, treat it as immutable. Charset: [A-Za-z0-9._:-], 1-256 chars."},"name":{"type":"string","maxLength":200},"timezone":{"type":"string","maxLength":64},"industry":{"type":"string"},"default_environment":{"type":"string"},"default_sales_motion":{"type":"string"},"default_recording_type":{"type":"string"},"pii_policy":{"type":"object","properties":{"redaction_level":{"type":"string","enum":["none","standard","aggressive"]},"retain_transcript_days":{"anyOf":[{"type":"integer","minimum":0},{"type":"string","enum":["forever"]}]},"retain_analysis_days":{"anyOf":[{"type":"integer","minimum":0},{"type":"string","enum":["forever"]}]},"redact_fields":{"type":"array","items":{"type":"string"}}},"additionalProperties":true},"settings":{"type":"object","additionalProperties":{}}},"required":["org_id"],"additionalProperties":false}}}},"responses":{"200":{"description":"Default Response"}}},"get":{"summary":"List orgs","tags":["Orgs"],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":100},"in":"query","name":"limit","required":false},{"schema":{"type":"string"},"in":"query","name":"cursor","required":false}],"responses":{"200":{"description":"Default Response"}}}},"/v1/orgs/{org_id}":{"get":{"summary":"Fetch an org","tags":["Orgs"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"org_id","required":true}],"responses":{"200":{"description":"Default Response"}}},"patch":{"summary":"Update an org","tags":["Orgs"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":200},"timezone":{"type":"string","maxLength":64},"industry":{"type":"string","nullable":true},"default_environment":{"type":"string","nullable":true},"default_sales_motion":{"type":"string","nullable":true},"default_recording_type":{"type":"string","nullable":true},"pii_policy":{"type":"object","properties":{"redaction_level":{"type":"string","enum":["none","standard","aggressive"]},"retain_transcript_days":{"anyOf":[{"type":"integer","minimum":0},{"type":"string","enum":["forever"]}]},"retain_analysis_days":{"anyOf":[{"type":"integer","minimum":0},{"type":"string","enum":["forever"]}]},"redact_fields":{"type":"array","items":{"type":"string"}}},"additionalProperties":true},"settings":{"type":"object","additionalProperties":{}}},"additionalProperties":false}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"org_id","required":true}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Soft-delete an org","tags":["Orgs"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"org_id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/v1/orgs/{org_id}/reps":{"post":{"summary":"Create (or upsert) a rep","tags":["Reps"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"rep_id":{"type":"string","minLength":1,"maxLength":256,"pattern":"^[A-Za-z0-9._:-]+$","description":"Opaque identifier from your system. Treat this like a foreign key — pass a stable ID (Salesforce User ID, HubSpot Owner ID, your internal UUID), not a display name. Display names (\"alex\", \"brooke\") work but cause real problems: collisions between people with the same first name, history loss on rename, no clean migration if employment changes. Once you set this for a rep or org, treat it as immutable. Charset: [A-Za-z0-9._:-], 1-256 chars."},"name":{"type":"string","maxLength":200},"email":{"type":"string","format":"email"},"metadata":{"type":"object","additionalProperties":{}}},"required":["rep_id"],"additionalProperties":false}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"org_id","required":true}],"responses":{"200":{"description":"Default Response"}}},"get":{"summary":"List reps in an org","tags":["Reps"],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":100},"in":"query","name":"limit","required":false},{"schema":{"type":"string"},"in":"query","name":"cursor","required":false},{"schema":{"type":"string"},"in":"path","name":"org_id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/v1/orgs/{org_id}/reps/{rep_id}":{"get":{"summary":"Fetch a rep","tags":["Reps"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"org_id","required":true},{"schema":{"type":"string"},"in":"path","name":"rep_id","required":true}],"responses":{"200":{"description":"Default Response"}}},"patch":{"summary":"Update a rep","tags":["Reps"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":200,"nullable":true},"email":{"type":"string","format":"email","nullable":true},"metadata":{"type":"object","additionalProperties":{}}},"additionalProperties":false}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"org_id","required":true},{"schema":{"type":"string"},"in":"path","name":"rep_id","required":true}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Soft-delete a rep","tags":["Reps"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"org_id","required":true},{"schema":{"type":"string"},"in":"path","name":"rep_id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/v1/industries":{"get":{"summary":"List industries","tags":["Reference"],"responses":{"200":{"description":"Default Response"}}}},"/v1/environments":{"get":{"summary":"List environments","tags":["Reference"],"responses":{"200":{"description":"Default Response"}}}},"/v1/sales-motions":{"get":{"summary":"List sales motions","tags":["Reference"],"responses":{"200":{"description":"Default Response"}}}},"/v1/recording-types":{"get":{"summary":"List recording types","tags":["Reference"],"responses":{"200":{"description":"Default Response"}}}},"/v1/personas":{"get":{"summary":"List sales personas","tags":["Personas"],"responses":{"200":{"description":"Default Response"}}}},"/v1/methodologies":{"get":{"summary":"List sales methodologies","tags":["Methodologies"],"responses":{"200":{"description":"Default Response"}}}},"/v1/orgs/{org_id}/reps/{rep_id}/persona":{"get":{"summary":"Current persona assignment","tags":["Personas"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"org_id","required":true},{"schema":{"type":"string"},"in":"path","name":"rep_id","required":true}],"responses":{"200":{"description":"Default Response"}}},"put":{"summary":"Manually set a rep persona","tags":["Personas"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"persona":{"type":"string","minLength":1},"justification":{"type":"string","maxLength":2000}},"required":["persona"],"additionalProperties":false}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"org_id","required":true},{"schema":{"type":"string"},"in":"path","name":"rep_id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/v1/orgs/{org_id}/reps/{rep_id}/persona/history":{"get":{"summary":"Persona assignment history","tags":["Personas"],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":100},"in":"query","name":"limit","required":false},{"schema":{"type":"string"},"in":"query","name":"cursor","required":false},{"schema":{"type":"string"},"in":"path","name":"org_id","required":true},{"schema":{"type":"string"},"in":"path","name":"rep_id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/v1/orgs/{org_id}/reps/{rep_id}/persona/assign":{"post":{"summary":"Async persona assignment from recordings","tags":["Personas"],"description":"Submit N recording_urls OR N analysis_ids. We run each through the pipeline (cached 30 days by URL), then meta-analyze to determine the rep's persona. 202 + job_id returned; final result delivered via persona.assigned webhook or polled via GET /v1/orgs/:org_id/reps/:rep_id/intel-jobs/:job_id.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"recording_urls":{"type":"array","items":{"type":"string","format":"uri"},"minItems":1,"maxItems":50},"analysis_ids":{"type":"array","items":{"type":"string","format":"uuid"},"minItems":1,"maxItems":50},"callback_url":{"type":"string","format":"uri"}},"additionalProperties":false}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"org_id","required":true},{"schema":{"type":"string"},"in":"path","name":"rep_id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/v1/orgs/{org_id}/reps/{rep_id}/methodology":{"get":{"summary":"Current methodology assignments (primary + secondary)","tags":["Methodologies"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"org_id","required":true},{"schema":{"type":"string"},"in":"path","name":"rep_id","required":true}],"responses":{"200":{"description":"Default Response"}}},"put":{"summary":"Manually set rep methodologies","tags":["Methodologies"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"primary":{"type":"string","minLength":1},"secondary":{"type":"string","minLength":1},"justification":{"type":"string","maxLength":2000}},"required":["primary"],"additionalProperties":false}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"org_id","required":true},{"schema":{"type":"string"},"in":"path","name":"rep_id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/v1/orgs/{org_id}/reps/{rep_id}/methodology/history":{"get":{"summary":"Methodology assignment history","tags":["Methodologies"],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":100},"in":"query","name":"limit","required":false},{"schema":{"type":"string"},"in":"query","name":"cursor","required":false},{"schema":{"type":"string"},"in":"path","name":"org_id","required":true},{"schema":{"type":"string"},"in":"path","name":"rep_id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/v1/orgs/{org_id}/reps/{rep_id}/methodology/assign":{"post":{"summary":"Async primary + secondary methodology assignment from recordings","tags":["Methodologies"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"recording_urls":{"type":"array","items":{"type":"string","format":"uri"},"minItems":1,"maxItems":50},"analysis_ids":{"type":"array","items":{"type":"string","format":"uuid"},"minItems":1,"maxItems":50},"callback_url":{"type":"string","format":"uri"}},"additionalProperties":false}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"org_id","required":true},{"schema":{"type":"string"},"in":"path","name":"rep_id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/v1/orgs/{org_id}/reps/{rep_id}/synthesis":{"post":{"summary":"Generate a strategic coaching synthesis for this rep","tags":["Synthesis"],"description":"Rolls up the rep's most recent completed analyses (or explicit analysis_ids) into a coaching summary with strengths, gaps, action plan, and score trends. 202 + job_id. Result delivered via profile.synthesized webhook.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"lookback_count":{"type":"integer","minimum":1,"maximum":50},"analysis_ids":{"type":"array","items":{"type":"string","format":"uuid"},"minItems":1,"maxItems":50},"callback_url":{"type":"string","format":"uri"}},"additionalProperties":false}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"org_id","required":true},{"schema":{"type":"string"},"in":"path","name":"rep_id","required":true}],"responses":{"200":{"description":"Default Response"}}},"get":{"summary":"Synthesis history","tags":["Synthesis"],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":100},"in":"query","name":"limit","required":false},{"schema":{"type":"string"},"in":"query","name":"cursor","required":false},{"schema":{"type":"string"},"in":"path","name":"org_id","required":true},{"schema":{"type":"string"},"in":"path","name":"rep_id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/v1/orgs/{org_id}/reps/{rep_id}/synthesis/latest":{"get":{"summary":"Latest synthesis for a rep","tags":["Synthesis"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"org_id","required":true},{"schema":{"type":"string"},"in":"path","name":"rep_id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/v1/orgs/{org_id}/reps/{rep_id}/intel-jobs/{job_id}":{"get":{"summary":"Poll a rep-intelligence batch job","tags":["Personas"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"org_id","required":true},{"schema":{"type":"string"},"in":"path","name":"rep_id","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"job_id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/v1/orgs/{org_id}/reps/{rep_id}/stats":{"get":{"summary":"Rep score aggregates and trend","tags":["Reps"],"parameters":[{"schema":{"type":"string","format":"date-time"},"in":"query","name":"from","required":false},{"schema":{"type":"string","format":"date-time"},"in":"query","name":"to","required":false},{"schema":{"type":"string","enum":["day","week","month"]},"in":"query","name":"granularity","required":false},{"schema":{"type":"string"},"in":"path","name":"org_id","required":true},{"schema":{"type":"string"},"in":"path","name":"rep_id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/v1/orgs/{org_id}/playbooks":{"post":{"summary":"Create a playbook (org-level or per-rep override)","tags":["Playbooks"],"description":"Create a sales playbook. Polymorphic scope: omit `rep_id` to create an **org-level** playbook (every rep in the org uses it as the baseline at analysis time, when `is_active=true`). Pass `rep_id` to create a **rep-level** playbook (overrides the org playbook for that rep only).\n\n**Resolution order at analysis time:**\n\n1. `options.playbook_content` (literal text on the analysis request)\n2. `options.playbook_id` (explicit lookup)\n3. Active rep-level playbook for the analysis's rep — *if `rep_id` is set on the analysis*\n4. Active org-level playbook for the analysis's org\n5. None (model uses default scoring)\n\nUse rep-level playbooks for A/B tests, per-coach customization, or consumer products where every end-user is a `rep` with their own rubric. The org-level playbook stays in place as the baseline — no need to disable it. See [PAR-185](https://linear.app/goparlay/issue/PAR-185).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"rep_id":{"type":"string","minLength":1,"maxLength":256,"description":"Optional. When set, scopes the playbook to a single rep within this org instead of the whole org. Per-rep playbooks override the org-level playbook for that rep at analysis time. Use for A/B tests, per-coach customization, or per-end-user flows in consumer products. The rep must already exist (create one first via POST /v1/reps). Omit this field to create an org-level playbook (every rep inherits it as the baseline)."},"name":{"type":"string","minLength":1,"maxLength":200,"description":"Display name for the playbook (e.g. \"Q2 2026 Outbound Playbook\")."},"content":{"type":"string","minLength":1,"maxLength":500000,"description":"Playbook body, typically markdown. Fed into every analysis for this org (or rep, if rep_id is set) when is_active=true. Max 500,000 chars."},"is_active":{"type":"boolean","description":"Default true. Multiple is_active=true playbooks at the same scope are allowed; the most recently-created one wins at analysis time."},"file_name":{"type":"string","maxLength":200,"description":"Original filename if the partner uploaded the playbook from disk."},"metadata":{"type":"object","additionalProperties":{},"description":"Free-form key/value bag for partner-side bookkeeping. Not interpreted by Parlay."}},"required":["content"],"additionalProperties":false}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"org_id","required":true}],"responses":{"200":{"description":"Default Response"}}},"get":{"summary":"List playbooks (org-level + per-rep, with filters)","tags":["Playbooks"],"description":"List playbooks belonging to an org, newest first. Returns both org-level and rep-level playbooks by default. Filters:\n\n- `rep_id=<slug>` → only that rep's playbooks\n- `scope=org` → only org-level (where `rep_id` is null in responses)\n- `scope=rep` → only rep-level (any rep in this org)\n- `active_only=true` → only `is_active=true` rows\n\nResponse rows carry a `rep_id` field that is `null` for org-level playbooks and the partner-supplied rep slug for rep-level ones.","parameters":[{"schema":{"type":"boolean"},"in":"query","name":"active_only","required":false,"description":"If true, only returns playbooks where is_active=true. Default false."},{"schema":{"type":"string","minLength":1,"maxLength":256},"in":"query","name":"rep_id","required":false,"description":"Filter to playbooks scoped to this rep only. Omit to see org-level + every rep-level playbook in the org."},{"schema":{"type":"string","enum":["org","rep"]},"in":"query","name":"scope","required":false,"description":"Filter by scope. `org` returns only org-level playbooks (where rep_id is null). `rep` returns only rep-level playbooks. Omit + omit `rep_id` to return everything. Mutually exclusive with `rep_id` (rep_id is more specific)."},{"schema":{"type":"integer","minimum":1,"maximum":100},"in":"query","name":"limit","required":false},{"schema":{"type":"string"},"in":"query","name":"cursor","required":false},{"schema":{"type":"string"},"in":"path","name":"org_id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/v1/orgs/{org_id}/playbooks/{id}":{"get":{"summary":"Fetch a playbook","tags":["Playbooks"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"org_id","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}},"patch":{"summary":"Update a playbook (bumps version on content change)","tags":["Playbooks"],"description":"If `content` changes, the prior version is appended to playbook_versions and version increments.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":200,"nullable":true},"content":{"type":"string","minLength":1,"maxLength":500000},"is_active":{"type":"boolean"},"metadata":{"type":"object","additionalProperties":{}}},"additionalProperties":false}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"org_id","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Soft-delete a playbook","tags":["Playbooks"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"org_id","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/v1/orgs/{org_id}/playbooks/{id}/versions":{"get":{"summary":"Version history","tags":["Playbooks"],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":100},"in":"query","name":"limit","required":false},{"schema":{"type":"string"},"in":"query","name":"cursor","required":false},{"schema":{"type":"string"},"in":"path","name":"org_id","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/v1/orgs/{org_id}/playbook-sources":{"post":{"summary":"Upload a playbook source material","tags":["Playbooks"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":200},"content":{"type":"string","minLength":1,"maxLength":500000},"source_type":{"type":"string","enum":["inline","url","transcript"]},"source_url":{"type":"string","format":"uri"}},"required":["title","content"],"additionalProperties":false}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"org_id","required":true}],"responses":{"200":{"description":"Default Response"}}},"get":{"summary":"List source materials","tags":["Playbooks"],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":100},"in":"query","name":"limit","required":false},{"schema":{"type":"string"},"in":"query","name":"cursor","required":false},{"schema":{"type":"string"},"in":"path","name":"org_id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/v1/orgs/{org_id}/playbook-sources/{id}":{"get":{"summary":"Fetch a source material","tags":["Playbooks"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"org_id","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Soft-delete a source material","tags":["Playbooks"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"org_id","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/v1/orgs/{org_id}/playbook-drafts":{"post":{"summary":"Generate a playbook draft from source materials (async)","tags":["Playbooks"],"description":"Queues a Gemini job that synthesizes the supplied source materials into a markdown playbook. 202 + draft_id returned; completion delivered via playbook.draft.completed webhook and polling GET /playbook-drafts/:id.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"source_material_ids":{"type":"array","items":{"type":"string","format":"uuid"},"minItems":1,"maxItems":50},"callback_url":{"type":"string","format":"uri"}},"required":["source_material_ids"],"additionalProperties":false}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"org_id","required":true}],"responses":{"200":{"description":"Default Response"}}},"get":{"summary":"List playbook drafts","tags":["Playbooks"],"parameters":[{"schema":{"type":"string","enum":["queued","processing","completed","failed","published"]},"in":"query","name":"status","required":false},{"schema":{"type":"integer","minimum":1,"maximum":100},"in":"query","name":"limit","required":false},{"schema":{"type":"string"},"in":"query","name":"cursor","required":false},{"schema":{"type":"string"},"in":"path","name":"org_id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/v1/orgs/{org_id}/playbook-drafts/{id}":{"get":{"summary":"Fetch a draft (poll for completion)","tags":["Playbooks"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"org_id","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/v1/orgs/{org_id}/playbook-drafts/{id}/publish":{"post":{"summary":"Publish a completed draft as the active playbook","tags":["Playbooks"],"description":"Inserts the draft's generated_content into playbooks (version 1, is_active=true) and marks the draft published_at.","parameters":[{"schema":{"type":"string"},"in":"path","name":"org_id","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/v1/orgs/{org_id}/prompts":{"post":{"summary":"Create a custom prompt","tags":["Prompts"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":200},"description":{"type":"string","maxLength":2000},"prompt_content":{"type":"string","minLength":1,"maxLength":20000},"prompt_type":{"type":"string","enum":["scoring_criterion","evaluation_focus","disqualifier","other"]},"order_index":{"type":"integer","minimum":0},"is_active":{"type":"boolean"}},"required":["title","prompt_content"],"additionalProperties":false}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"org_id","required":true}],"responses":{"200":{"description":"Default Response"}}},"get":{"summary":"List custom prompts (ordered)","tags":["Prompts"],"parameters":[{"schema":{"type":"boolean"},"in":"query","name":"active_only","required":false},{"schema":{"type":"string"},"in":"path","name":"org_id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/v1/orgs/{org_id}/prompts/{id}":{"get":{"summary":"Fetch a prompt","tags":["Prompts"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"org_id","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}},"patch":{"summary":"Update a custom prompt","tags":["Prompts"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":200},"description":{"type":"string","maxLength":2000,"nullable":true},"prompt_content":{"type":"string","minLength":1,"maxLength":20000},"prompt_type":{"type":"string","enum":["scoring_criterion","evaluation_focus","disqualifier","other"]},"order_index":{"type":"integer","minimum":0},"is_active":{"type":"boolean"}},"additionalProperties":false}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"org_id","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Soft-delete a prompt","tags":["Prompts"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"org_id","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/v1/orgs/{org_id}/prompts/order":{"put":{"summary":"Bulk reorder custom prompts","tags":["Prompts"],"description":"Body: {ids: [...]} — new order_index is the position in the array. Atomic.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"ids":{"type":"array","items":{"type":"string","format":"uuid"},"minItems":1}},"required":["ids"],"additionalProperties":false}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"org_id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/v1/analyses/{id}/chat":{"post":{"summary":"Ask Scout a question about this analysis","tags":["Chat"],"description":"Returns the full response (non-streaming). SSE streaming variant lands in Phase 5.B. Chat history is persisted per-analysis; pass /chat repeatedly to maintain conversation.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","minLength":1,"maxLength":4000}},"required":["message"],"additionalProperties":false}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/v1/analyses/{id}/chat/welcome-questions":{"get":{"summary":"4 AI-generated starter questions tailored to this call","tags":["Chat"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/v1/analyses/{id}/chat/history":{"get":{"summary":"Full chat history for this analysis","tags":["Chat"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Clear chat history for this analysis","tags":["Chat"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/v1/analyses/{id}/disposition":{"post":{"summary":"Tag a disposition on an analysis (upsert)","tags":["Dispositions"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"disposition":{"type":"string","enum":["sold","lost","canceled","undispositioned"]},"notes":{"type":"string","maxLength":2000},"deal_amount":{"type":"number","minimum":0},"deal_closed_at":{"type":"string","format":"date-time"}},"required":["disposition"],"additionalProperties":false}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}},"get":{"summary":"Fetch the disposition for an analysis","tags":["Dispositions"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}},"patch":{"summary":"Update a disposition","tags":["Dispositions"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"disposition":{"type":"string","enum":["sold","lost","canceled","undispositioned"]},"notes":{"type":"string","maxLength":2000},"deal_amount":{"type":"number","minimum":0},"deal_closed_at":{"type":"string","format":"date-time"}},"additionalProperties":false}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Clear a disposition","tags":["Dispositions"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/v1/orgs/{org_id}/dispositions":{"get":{"summary":"List dispositions for an org","tags":["Dispositions"],"parameters":[{"schema":{"type":"string","enum":["sold","lost","canceled","undispositioned"]},"in":"query","name":"disposition","required":false},{"schema":{"type":"string","format":"date-time"},"in":"query","name":"from","required":false},{"schema":{"type":"string","format":"date-time"},"in":"query","name":"to","required":false},{"schema":{"type":"integer","minimum":1,"maximum":100},"in":"query","name":"limit","required":false},{"schema":{"type":"string"},"in":"query","name":"cursor","required":false},{"schema":{"type":"string"},"in":"path","name":"org_id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/v1/orgs/{org_id}/insights/generate":{"post":{"summary":"Generate an org insights snapshot (async)","tags":["Insights"],"description":"Aggregates the org's completed analyses in the supplied window (default last 30 days), runs a Gemini meta-analysis, and persists an insights_snapshots row. 202 + job_id. Webhook: insights.generated.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"period_type":{"type":"string","enum":["daily","weekly","monthly","custom"]},"start_date":{"type":"string","format":"date-time"},"end_date":{"type":"string","format":"date-time"},"callback_url":{"type":"string","format":"uri"}},"additionalProperties":false}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"org_id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/v1/orgs/{org_id}/insights":{"get":{"summary":"Fetch the most recent insights snapshot","tags":["Insights"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"org_id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/v1/orgs/{org_id}/insights/history":{"get":{"summary":"List insight snapshots over time","tags":["Insights"],"parameters":[{"schema":{"type":"string","enum":["daily","weekly","monthly","custom"]},"in":"query","name":"period_type","required":false},{"schema":{"type":"integer","minimum":1,"maximum":100},"in":"query","name":"limit","required":false},{"schema":{"type":"string"},"in":"query","name":"cursor","required":false},{"schema":{"type":"string"},"in":"path","name":"org_id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/v1/orgs/{org_id}/leaderboard":{"get":{"summary":"Rank reps in an org","tags":["Insights"],"description":"Pure SQL aggregate. sort_by: score (overall_avg desc), volume (analyses_count desc), improvement (first-half vs second-half delta). No AI, no cost.","parameters":[{"schema":{"type":"string","enum":["7d","30d","90d"]},"in":"query","name":"period","required":false},{"schema":{"type":"string","enum":["score","volume","improvement"]},"in":"query","name":"sort_by","required":false},{"schema":{"type":"integer","minimum":1,"maximum":100},"in":"query","name":"limit","required":false},{"schema":{"type":"string"},"in":"path","name":"org_id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/v1/webhooks/stripe":{"post":{"summary":"Stripe webhook receiver (HMAC-verified)","tags":["Webhooks"],"responses":{"200":{"description":"Default Response"}}}},"/":{"get":{"responses":{"200":{"description":"Default Response"}}}}},"servers":[{"url":"http://localhost:3000","description":"production"}],"security":[{"ApiKeyAuth":[]}],"tags":[{"name":"Health","description":"Service health and platform status"},{"name":"Analyses","description":"Submit and retrieve pitch scoring analyses"},{"name":"Orgs","description":"Partner org management"},{"name":"Reps","description":"Rep management"},{"name":"Keys","description":"API key lifecycle"},{"name":"Webhooks","description":"Webhook registration and delivery"},{"name":"Personas","description":"Rep persona intelligence"},{"name":"Methodologies","description":"Rep methodology intelligence"},{"name":"Synthesis","description":"Profile synthesis"},{"name":"Insights","description":"Org-level insights"},{"name":"Playbooks","description":"Playbook management + AI drafting"},{"name":"Prompts","description":"Custom AI prompts"},{"name":"Scoring","description":"Scoring profile config"},{"name":"Chat","description":"Scout AI chat"},{"name":"Dispositions","description":"Call dispositions"},{"name":"Practice","description":"Practice sessions"},{"name":"Bulk","description":"Batch and export"},{"name":"Usage","description":"Usage and billing"},{"name":"Audit","description":"Audit log"}]}