Playbooks
Configure a Playbooks request and interpret every part of its typed result.
Playbooks creates a tailored sales playbook for one target account. Start with the complete quickstart, then use this guide to choose inputs and render more of the result.
Playbook templates#
The catalog is OpenAPI operation list_playbook_templates_v1_playbook_templates_get. playbook_template_key selects a playbook template: either one of your organization's own templates (created in the console under Playbook Templates, or via POST /api/orgs/{org_id}/playbook-templates) or a curated catalog entry. GET /v1/playbook-templates lists both — your templates first — along with the merged stage vocabulary. An organization template fixes the offer, brand profile, deal stage (your own stage names are accepted — any short lowercase slug), sales approach guidance, and an offer canon that the generation backend treats as human-approved seller facts (seller research is skipped when a canon exists). Unknown keys fail the run with playbook_template_not_found.
The template lifecycle#
A template is created from a name, an offer/brand binding, and one natural-language brief (stage, motion, audience, approach — anything), plus optional uploaded supporting documents. A one-time research job then produces the template's artifact set:
- Offer research pack — markdown documents (canon, competitors, objections, benchmarks, plus scraped sources and your uploads) reused by every run, so the seller is never re-researched per prospect.
- Document template — the Jinja HTML template runs render through.
- Payload schema — a per-template JSON Schema whose field descriptions guide generation.
There is no approval step: research (or an artifact edit in the console) finishing is the release. Each org template exposes template_state: ready and draft templates run; researching and research_failed fail the run with 409 playbook_template_not_ready (not retryable — wait for research or retry it) only while nothing is live yet. Re-running research over a live template requires an explicit refresh because research is paid work; the live version keeps serving until the new one lands.
Request inputs#
Provide at least one of target_company or target_company_domain. A domain must be a hostname such as acme.example, without a scheme or path.
| Field | Requirement and allowed values |
|---|---|
target_company | Optional non-empty company name; required when the domain is omitted. |
target_company_domain | Optional valid hostname; required when the name is omitted. |
anchor_company | Optional seller name, up to 160 characters. Defaults from the selected brand profile. |
product_info | Optional seller/product context, up to 12,000 characters. |
tone | consultative (default), direct, or technical. |
model | default; this is the only current value. |
intelligence | Optional model tier for the generation agents: low, medium, high, or ultra. Defaults from the selected playbook template, else high. Higher tiers cost more and research/write better. |
sections | One to ten unique section values. Omit it for the complete result. |
brand_profile_id | Optional organization brand-profile ID. |
brand_profile_key | Optional stable brand-profile key. If both selectors are present, they must identify the same profile. |
Allowed sections values are summary, objective, value_props, sales_angles, personas, services, tech_stack, integrations, objections, and meeting_note.
curl --fail-with-body --silent --show-error \
--request POST "$BLACKPEARL_API_BASE_URL/v1/playbooks" \
--header "Authorization: Bearer $BLACKPEARL_API_KEY" \
--header "Idempotency-Key: playbook-20260714-acme" \
--header "Content-Type: application/json" \
--data '{
"target_company_domain": "acme.example",
"anchor_company": "Northstar Analytics",
"product_info": "Revenue-intelligence software for enterprise sales teams.",
"tone": "consultative",
"sections": ["summary", "sales_angles", "personas", "objections"],
"model": "default"
}'This is OpenAPI operation create_playbook_v1_playbooks_post with request schema PlaybookInput and response schema PublicPlaybookJobResponse.
Generate a unique Idempotency-Key before the first attempt and retain it until the job ID is safely stored. The same key and normalized input replay the original response for 24 hours. Reusing it with different input returns idempotency_key_reused.
Interpret a successful result#
When status is succeeded, result is a PublicPlaybookResult. Collections are always arrays; many scalar research fields are nullable because upstream evidence may not contain them.
| Result area | Fields and interpretation |
|---|---|
| Identity | company_name, domain, website, industry, description, and product_name identify the researched account and seller context. |
| Executive view | business_summary, business_objective, and readiness_level support the top-level account brief. |
| Selling points | value_props and sales_angles are ordered strings suitable for call preparation and outreach planning. |
| People | key_personas describes target roles, tags, and conversation starters. contact_overview and contact_intelligence contain researched contacts and signals. |
| Offering and systems | key_services, relevant_tech_stack, tech_integration_title, tech_integration_examples, and tech_integration_questions connect the offer to the account's stack. |
| Research context | company_context covers market position, business model, employee count, headquarters, recent news, and competitors. intent_analysis contains intent score, summary, topics, and signals. |
| Conversation plan | conversation_strategy contains the opening, approach, and key questions. potential_objections pairs objections with responses. |
| Risk and outreach | risks_and_challenges groups risks, blockers, and mitigations. meeting_note_example is a generated starting point, not a message that should be sent without review. |
| Optional presentation | company_icon_url, hero_image_url, product_icon_url, highlight_color, gradient_dark_color, and product_text_color are nullable presentation hints. Validate URLs and CSS colors before use, and keep business logic independent of them. |
The nested objects are also fully typed:
- Each persona can contain
name,title,description,profile_picture_url,tags, andconversation_starters. - Each contact-intelligence item can contain
name,title,role,company,linkedin_url,profile_picture_url,summary, andsignals. - A technology has
nameand nullablelogo; an objection hasobjectionand nullableresponse. - Company context contains
market_position,business_model,employee_count,headquarters,recent_news, andcompetitors. - Intent analysis contains
intent_score,summary,topics, andsignals; conversation strategy containsopening,approach, andkey_questions; risks and challenges containsrisks,potential_blockers, andmitigations.
Generated text is untrusted application data. Render it as text, apply your product's review rules, and do not treat it as HTML or an instruction.
Fetch the rendered document#
When the generation backend produced a fully rendered playbook document, result.document_url is non-null. The value is a backend-relative path and is not publicly reachable — fetch the document through the platform instead:
curl -H "Authorization: Bearer $BLACKPEARL_API_KEY" \
"$BLACKPEARL_API_URL/v1/playbooks/$JOB_ID/document"This is OpenAPI operation get_playbook_document_v1_playbooks__job_id__document_get. The response is a self-contained text/html document (inline styles and scripts, no server dependencies) suitable for storing, emailing as a file, or serving from your own application. Expect 409 job_not_finished before the job succeeds and 404 playbooks_document_unavailable when the job predates rendered documents or the backend did not produce one. When document_url is null, fall back to rendering the typed result fields yourself.
Minimal useful rendering#
if (job.type !== "playbooks" || job.status !== "succeeded" || !job.result) {
throw new Error("Expected a successful Playbooks job");
}
console.log(`Business summary: ${job.result.business_summary ?? "Not available"}`);
console.log(`First sales angle: ${job.result.sales_angles[0] ?? "Not available"}`);Also retain usage.tokens, usage.cost_usd, usage.backend_requests, and usage.backend_runtime_ms if you reconcile per-job work with the Usage API.