Extracting Key Points, Narrative, Sources, and Reference Metadata
In my previous AI blog post, we covered the very basics of submitting prompts via the OpenAI API from Salesforce. This post goes a bit deeper into the processing of the payload that OpenAI gives back from the /responses endpoint and persisting it in Salesforce with traceability, governance, and repeatability.
We focus specifically on:
- Requesting structured output from the model
- Parsing the Responses payload safely in Apex
- Accessing key points, narrative summaries, sources, and reference metadata
- Storing and rendering results in Salesforce without brittle parsing logic
High-Level Architectural Overview
A clean integration separates responsibilities. Anything else becomes technical debt immediately.
Recommended layers:
- Configuration
- Named Credential for OpenAI
- Custom Metadata for model, temperature, and limits
- Transport
- Apex service – responsible only for HTTP callouts and errors
- Domain
- Request builders and response DTOs
- Payload parsing and validation
- Persistence & UI
- Store structured results in Salesforce
- Render via LWC, Flow, or Experience Cloud
Do not put all of this into one Apex class. That’s amateur hour.
Named Credential Setup
Use an External Credential + Named Credential.
- Base URL:
https://api.openai.com - Auth: Bearer token stored securely
- Endpoint usage in Apex:
callout:OpenAI_NC/v1/responses
This avoids security issues, hardcoded secrets, Remote Site Settings, and deployment nightmares.
** This cannot be emphasized enough… Use Named Credentials in Salesforce!
Why the Responses Endpoint Matters
The Responses API is designed for:
- Structured output
- Tool-based responses
- Multi-part content
- Usage metadata
If you’re still calling legacy chat endpoints and parsing text blobs, you’re behind.
What You Should Ask the Model to Return
For most transactions, you can return
- Key points
- Narrative
- Sources
- Reference payload
You do not get this reliably by asking politely in natural language.
You get it by enforcing JSON schema output.
Target Output Shape
This is the structure you want Salesforce to receive and process:
{
"keyPoints": ["...", "..."],
"narrative": "...",
"sources": [
{
"title": "...",
"url": "...",
"publisher": "...",
"snippet": "...",
"confidence": 0.92
}
],
"references": {
"model": "gpt-4.1-mini",
"responseId": "resp-abc123",
"usage": {
"inputTokens": 1200,
"outputTokens": 350,
"totalTokens": 1550
}
}
}
This is what makes downstream processing sane.
Enforce Structured Output
The Responses API allows you to specify a response_format using a strict JSON schema.
If you don’t:
- The model may return prose
- You’ll end up regex-parsing text
- Your integration will eventually break
Key Rules
- Set
"strict": true - Disable additional properties
- Make required fields explicit
If the model cannot comply, it fails fast—which is exactly what you want in a system integration.
Making the Callout from Apex
At a high level:
- Build a request with:
- Model
- Temperature
- Persona
- Sentiment
- Token limits
- Messages (system + user)
- JSON schema response format
- POST to
/v1/responses - Deserialize safely
- Extract your structured payload from the
outputarray
The Responses payload is not a flat object. You must walk it.
Understanding the Responses Payload
At runtime, the API returns:
- Top-level metadata (
id,model,usage) - An
outputarray - Each output item contains
content - Each content item may contain text, tool output, or structured JSON
When you enforce JSON schema output, your structured result typically appears as JSON text embedded in the output content.
That means:
- You deserialize the outer payload loosely
- Then attempt to parse inner text as JSON
- If it parses cleanly, you’ve found your result
This is intentional. It allows the API to support multiple content types without breaking clients.
Extracting Key Points and Narrative
Once parsed, access is trivial:
- Key points
Use as bullet lists, highlights, or executive summaries. - Narrative
This is your human-readable summary—store it as Long Text and render it directly.
Do not concatenate these back into prose. Keep them structured.
Handling Sources Correctly
If you ask the model for sources without providing a corpus, it will hallucinate.
That’s not an OpenAI bug— it is a design flaw.
Valid Source Strategies
- Salesforce records you pass into the prompt (record URLs)
- Knowledge articles
- ContentDocument links
- Data Cloud or external datasets you retrieved yourself
What to Tell the Model
Be explicit:
Only cite sources provided in the input.
If no source supports a claim, omit it.
Then store sources as structured objects, not formatted text.
Sources vs Reference Payload
These serve different purposes and should be stored separately.
Sources
Reader-facing
- URLs
- Titles
- Snippets
- Confidence or relevance
These justify the narrative.
Reference Payload
System-facing
- Response ID
- Model used
- Token usage
- Raw response JSON (optional but recommended)
This enables:
- Auditing
- Cost tracking
- Support diagnostics
- Model performance analysis
Conflating the two is sloppy design.
What you should persist in Salesforce
At minimum, store:
- Narrative (Long Text)
- Key points (JSON or newline-delimited)
- Sources (JSON)
- Response ID
- Model
- Input / output / total tokens
- Raw response payload (optional, but extremely useful)
Whether this lives in AI_Response__c, a related object, or a platform event depends on your use case—but skipping persistence entirely is short-sighted.
Common Failure Modes
Output isn’t JSON
- Fix: strict schema + retry once with lower temperature
Sources are nonsense
- Fix: restrict citations to supplied context
Schema drift breaks parsing
- Fix: deserialize top-level payload as untyped, map selectively
Token explosions
- Fix: chunk data, summarize iteratively, cap
max_output_tokens
No audit trail
- Fix: store response ID, model, and usage every time
Where This Becomes Real
Once you’ve implemented this correctly, you can build:
- Executive summaries with cited sources
- Sales or service insights with traceable evidence
- Knowledge synthesis with governance
- AppExchange-grade AI features that won’t embarrass you later
This is the difference between “we added AI” and “we built an AI-powered system.”
Final Take
Calling the OpenAI API from Salesforce is easy.
Processing the Responses payload correctly is the actual work.
If you:
- Enforce structured output
- Parse defensively
- Separate sources from reference metadata
- Persist results with traceability
You end up with something enterprise-ready, where you can answer the big question that will always be asked… “where did this come from?”

We would love to hear your comments!