Skip to main content

Anthropic Claude AI

Claude is used for AI-powered call summarization in Client Portal. When a sales call produces a transcript, Claude analyzes it to extract disposition, sentiment, key points, buying signals, and objections -- replacing manual note-taking and providing consistent, structured intelligence.

Configuration

SettingValue
API URLhttps://api.anthropic.com/v1/messages
Auth Headerx-api-key: {ANTHROPIC_API_KEY}
API Versionanthropic-version: 2023-06-01
Modelclaude-sonnet-4-5-20250929 (configurable via ANTHROPIC_MODEL env)
Max Tokens1024
Env VariableANTHROPIC_API_KEY (Supabase secret)

Edge Function: summarize-sales-call

Trigger

Called automatically by ghl-call-webhook (or ghl-sales-webhook) when a call transcript meets these conditions:

  1. Transcript text is longer than 50 characters (after flattening)
  2. Transcript does not match the voicemail greeting pattern

Can also be triggered manually via the "Summarize" button in the Sales Call Detail drawer.

Request

{
"call_id": "uuid",
"transcript": "Full call transcript text..."
}

Process Flow

AI Output Schema

Claude returns a JSON object with the following structure:

{
"disposition": "Future Potential",
"key_points": [
"Prospect runs a 12-person legal search firm in NYC",
"Currently uses in-house researchers for candidate sourcing",
"Expressed interest in patent litigation market coverage",
"Asked about pricing and timeline for validation sprint"
],
"sentiment": "interested",
"action_items": [
"Send pricing deck for Market Validation Sprint",
"Schedule follow-up call for next Tuesday"
],
"engagement_assessment": "Strong prospect -- actively looking for market intelligence solution. Decision timeline is 2-4 weeks.",
"conversation_quality": "warm",
"interest_level": 7,
"objections": [
"Concerned about overlap with existing research team"
],
"buying_signals": [
"Asked about pricing unprompted",
"Mentioned specific market they want covered",
"Asked about onboarding timeline"
]
}

Field Definitions

FieldTypeValuesDescription
dispositionstringOne of 9 canonicalThe AI's best-fit disposition for the call
key_pointsstring[]3--5 itemsMost important facts from the conversation
sentimentstringinterested, skeptical, not_interested, excited, neutralProspect's emotional tone
action_itemsstring[]VariableSpecific next steps needed
engagement_assessmentstringFree text1--2 sentence commercial assessment
conversation_qualitystringcold, neutral, warm, hotTemperature of the conversation
interest_levelnumber1--10Numeric interest rating
objectionsstring[]VariableConcerns or pushback raised
buying_signalsstring[]VariablePositive indicators of purchase intent

Disposition Rules

The system prompt instructs Claude to choose from the 9 canonical dispositions with specific guidance:

DispositionWhen to Use
VoicemailTranscript is a voicemail greeting or automated message
GatekeeperReceptionist/assistant answered, decision-maker not reached
Incorrect NumberWrong person, number not in service
Not InterestedProspect explicitly declined or shut the conversation down
Callback RequestedProspect literally said "call me back", "try me later" -- do NOT use as default
Future PotentialAny engaged conversation without a meeting booked. Correct choice for neutral-to-positive calls. When in doubt between Callback Requested and Future Potential, choose Future Potential.
Meeting BookedA meeting or demo was scheduled during the call
Do Not ContactProspect explicitly asked not to be contacted again
No AnswerOnly if transcript shows no real interaction
Disposition Priority

AI disposition overwrites the regex-inferred disposition from the webhook handler. The ghl-call-webhook handler awaits the AI response and uses the AI disposition as the final value. BDR-confirmed dispositions from GHL's disposition workflow take highest priority and are never overwritten by AI.

Disposition Validation

The AI response is validated against the canonical list before being applied:

const VALID_DISPOSITIONS = [
"No Answer", "Voicemail", "Gatekeeper", "Incorrect Number",
"Not Interested", "Callback Requested", "Future Potential",
"Meeting Booked", "Do Not Contact",
];

const aiDisposition = VALID_DISPOSITIONS.includes(summary.disposition)
? summary.disposition
: null;

If the AI returns an invalid disposition, it is ignored and the existing disposition is preserved.

Database Updates

sales_calls Table Updates

ColumnSourceDescription
ai_summaryFull JSONComplete AI analysis object (JSONB)
ai_summary_textConstructedPlain-text summary for display
dispositionsummary.dispositionCanonical disposition (if valid)
disposition_reasonsummary.engagement_assessmentPrefixed with "AI: "
conversation_qualitysummary.conversation_qualitycold/neutral/warm/hot
interest_levelsummary.interest_level1--10 rating
objectionssummary.objectionsArray of objection strings
buying_signalssummary.buying_signalsArray of buying signal strings
notesPlain-text summaryKey points + sentiment + interest
ai_processed_atTimestampWhen AI processing completed

sales_prospects Table Updates (Auto-Disposition)

After updating the call, the function automatically adjusts the prospect's engagement state:

AI DispositionEngagement LevelFollow-Up
Meeting Bookedmeeting_setCleared (meeting is the follow-up)
Future Potentialengaged7 days from now
Callback Requested (warm/hot)engaged2 days from now
Callback Requested (cold/neutral)contacted3 days from now
Not Interestednurturing14 days from now
Do Not Contactclosed_lostCleared, do_not_contact = true
Gatekeepercontacted2 days from now
Voicemailcontacted1 day (first 3 VMs), 7 days (after)
Incorrect Numberclosed_lostCleared
No AnswercontactedNone

The follow-up includes context in next_follow_up_notes:

"Future potential. Interest: 7/10. Follow up in 1 week."
"Voicemail #3. Retry tomorrow."
"warm conversation. Interest: 8/10. Follow up in 2 days."

System Prompt

The full system prompt provides Claude with business context about 1 Hour Recruitment's service model:

You are an AI assistant for 1 Hour Recruitment, a company that sells
market intelligence services to boutique legal search firms.

You are analyzing a sales call transcript between a 1HR sales rep and
a prospective client (a legal search firm owner/partner).

Extract the following in JSON format: { ... }

Disposition rules: ...
- When in doubt between Callback Requested and Future Potential,
choose Future Potential.

Be concise and specific. Focus on commercial signals relevant to
closing the deal. Return ONLY valid JSON, no other text.

Error Handling

ErrorBehavior
ANTHROPIC_API_KEY not setReturns 500 with descriptive error
Claude API error (4xx/5xx)Returns 500 with Claude's error message
JSON parse failureTries regex extraction of JSON from response
Invalid dispositionPreserves existing disposition, still saves summary
Auto-disposition failureLogged, does not fail the summary response

Manual Trigger

Users can trigger summarization from the UI via two paths:

  1. SummarizeCallButton (src/components/sales/SummarizeCallButton.tsx) -- one-click on a call that already has a transcript.
  2. PasteTranscriptDialog (src/components/sales/PasteTranscriptDialog.tsx) -- paste a transcript manually for calls without one.

Both call the edge function with the same { call_id, transcript } payload.

  • GHL Webhooks -- Auto-triggers AI summarization when transcripts arrive
  • GHL Overview -- Architecture of the GHL integration that feeds transcripts