Find supported PII
Scan the final transcript for supported identifiers and contact details, including card numbers, SSNs, emails and US phone numbers.
PyAI Trace for GPT-Live
Customer conversations contain sensitive details. Add post-call PII review and transcript redaction to your GPT-Live recordings, while keeping your voice stack.
Post-call sensitive-data review · Trace beta
A sensitive detail.
A cleaner record.
“Please send the annual pricing to [REDACTED_EMAIL]. Friday works for our review.”
Illustrative example. Actual findings depend on the recording, transcription and enabled scan. Redaction applies to the transcript, not the source audio.
From conversation to review
Scan the final transcript for supported identifiers and contact details, including card numbers, SSNs, emails and US phone numbers.
Use the redacted result in the downstream review workflow you build. Keep source recordings and their access controls separate.
Read the scan summary alongside the transcription result. A successful job and a clean PII scan answer different questions.
The supported setup
Your application connects the recording to PyAI. No change to GPT-Live’s conversation model or delegated backend is required for this post-call path.
Use a finalized GPT-Live stored recording when available, or the recording from your own audio system. Capture both sides and apply your recording permissions.
Enable the required Trace entitlement. Prepare a compatible recording and submit it with trace: true. The single-job PII path does not support channel separation or diarization.
Wait for the transcription job to complete or handle its completion webhook. Read its redacted transcript and Trace summary, then route them into your review process.
Connect an OpenAI project key once through PyAI’s owner/admin management API. Your backend then sends the completed session ID using its PyAI key. PyAI fetches the recording and returns a normal transcription job for polling or a signed completion webhook.
curl https://api.pyai.com/v1/transcription/jobs \
-H "Authorization: Bearer $PYAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"gpt_live": { "session_id": "YOUR_COMPLETED_SESSION_ID" },
"trace": true,
"numerals": true
}'The one-time connection uses PUT /projects/{id}/integrations/gpt-live with an authenticated owner/admin session. Repeating a session import returns the same job; conflicting options are rejected. Your app must notify PyAI after each stored recording is finalized. This does not discover every session in an OpenAI account.
This server-side Node.js 22+ example downloads the real stored recording, uploads it to Hear with Trace, and saves the scanned transcript and Trace summary to a local JSON file. No public recording URL or npm packages are needed.
store: true in the session configuration when you create the GPT-Live session. Save the session ID.session.close, wait for session.closed, and allow the recording to finalize. Stored recordings are unavailable with Zero Data Retention and expire after 30 days.OPENAI_API_KEY, PYAI_API_KEY and GPT_LIVE_SESSION_ID on your server.# Set OPENAI_API_KEY, PYAI_API_KEY and GPT_LIVE_SESSION_ID
# in your server environment, then run the downloaded file:
node gpt-live-trace.mjs// Node.js 22+. Server-side only. No npm dependencies.
// Start GPT-Live with store: true; wait for session.closed and recording finalization.
import { writeFile } from "node:fs/promises";
import { pathToFileURL } from "node:url";
import { setTimeout as sleep } from "node:timers/promises";
export async function run(env = process.env, { request = fetch, pause = sleep } = {}) {
const required = (name) => {
if (!env[name]) throw new Error(`Set ${name} on your server.`);
return env[name];
};
const auth = { Authorization: `Bearer ${required("PYAI_API_KEY")}` };
const jobs = "https://api.pyai.com/v1/transcription/jobs";
async function checked(url, options = {}) {
const response = await request(url, {
...options, redirect: "error", signal: AbortSignal.timeout(120_000),
});
if (!response.ok) {
// Do not log provider response bodies, credentials or signed URLs.
throw new Error(`HTTP ${response.status} from ${new URL(url).host}. Check access, entitlement and recording readiness.`);
}
return response;
}
// Resume an existing job after a polling interruption instead of paying twice.
let jobId = env.PYAI_JOB_ID;
if (!jobId) {
const sessionId = required("GPT_LIVE_SESSION_ID");
const recording = await checked(
`https://api.openai.com/v1/live/sessions/${encodeURIComponent(sessionId)}/content`,
{ headers: { Authorization: `Bearer ${required("OPENAI_API_KEY")}` } },
);
// Bound memory for this example. Stream large recordings in your production worker.
const chunks = [];
let bytes = 0;
for await (const chunk of recording.body) {
bytes += chunk.length;
if (bytes > 64 * 1024 * 1024) throw new Error("Example limit: 64 MiB recording.");
chunks.push(chunk);
}
if (!bytes) throw new Error("The stored recording is empty.");
const form = new FormData();
form.set("audio", new Blob(chunks, { type: "audio/wav" }), "gpt-live.wav");
form.set("trace", "true");
form.set("numerals", "true");
// Hear mixes both channels for this path. Do not set channel or diarize.
// fetch supplies the multipart boundary; do not set Content-Type yourself.
// This multipart POST has no documented idempotency support: never auto-retry it.
const created = await (await checked(jobs, { method: "POST", headers: auth, body: form })).json();
jobId = created.job_id;
if (typeof jobId !== "string" || !jobId) throw new Error("Missing job_id.");
console.log(`Submitted ${jobId}. To resume, set PYAI_JOB_ID=${jobId}.`);
}
for (let attempt = 0; attempt < 450; attempt++) {
const job = await (await checked(`${jobs}/${encodeURIComponent(jobId)}`, { headers: auth })).json();
if (job.status === "failed" || job.status === "cancelled") {
throw new Error(`Job ${jobId} ${job.status}. Inspect its error in your secured backend.`);
}
if (job.status === "completed") {
let result = job.result;
if (!result && job.result_url) {
const url = new URL(job.result_url);
if (url.protocol !== "https:" || url.username || url.password) throw new Error("Invalid result URL.");
// A signed storage URL needs no API key. Never forward either provider's key.
result = await (await checked(url.href)).json();
}
if (typeof result?.text !== "string" || !result.trace ||
typeof result.trace.verdict !== "string" ||
!Number.isInteger(result.trace.n_pii) || result.trace.n_pii < 0 ||
typeof result.trace.redacted !== "boolean") {
throw new Error("Completed job is missing a valid Trace result.");
}
return { job_id: jobId, ...result };
}
if (!["queued", "running"].includes(job.status)) throw new Error("Unknown job status.");
await pause(2_000);
}
throw new Error(`Polling limit reached. Resume with PYAI_JOB_ID=${jobId}; do not resubmit.`);
}
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
try {
const result = await run();
const output = `trace-result-${Date.now()}.json`;
await writeFile(output, JSON.stringify(result, null, 2), { mode: 0o600, flag: "wx" });
console.log(`Saved ${output}. PII matches: ${result.trace.n_pii}.`);
// result.text is the scanned transcript; result.trace holds verdict/n_pii/redacted.
// Review coverage: unmatched sensitive data can remain; source audio is not redacted.
} catch (error) {
console.error(error.message);
process.exitCode = 1;
}
}
Reads result.text and result.trace, including results returned through a signed download URL. Both audio channels are mixed for this scan; speaker attribution is not retained. The example limits recordings to 64 MiB and keeps API keys on your server. It redacts supported matches in the transcript, not the source audio.
If polling stops, set PYAI_JOB_ID to the printed job ID and rerun to resume. If the initial upload fails without returning an ID, check your jobs before resubmitting: multipart uploads do not support idempotent retries. Hear and Trace usage are billed; uploaded audio may be retained for up to 7 days and results for 30 days under the current API policy.
Validation: checked against the current API contracts and automated mocked responses. A live GPT-Live → Trace run has not yet been verified. OpenAI recording setup · Trace setup guide.
Know exactly what you are adding
Make the rest of the call useful
Recap turns speaker-labelled conversations into summaries, action items and structured fields. Validate the inputs for each path when combining it with Trace.
See Recap for GPT-Live →Before you build
No. This recording-based integration detects supported PII patterns and redacts the resulting transcript. It does not establish HIPAA compliance or include the full HIPAA rule pack on this path. Broader Trace coverage requires a supported, explicitly enabled call path.
Yes, through the documented recording-based Hear + Trace path. Your application obtains the call recording, prepares a compatible audio input and submits an async transcription job with trace enabled. This is an application-level integration, not a native GPT-Live connector.
The async recording path performs deterministic PII scanning and transcript redaction for supported patterns: SSNs, credit-card numbers, CVV in context, email addresses and US phone numbers. It returns a Trace summary with the transcription result. Detection depends on transcript quality and supported patterns.
No. The external recording path described here covers deterministic PII scanning. Full rule-pack scorecards, semantic findings and audit hashes are available on other eligible Trace-enabled paths; do not assume they are produced for an arbitrary GPT-Live recording.
This path reviews the completed recording. It does not intercept GPT-Live playback or block its backend tools. Keep live permissions, consent handling and action controls in your application.
The documented trace option cannot be combined with channel or diarize in the same Hear job. Keep the original recording and speaker-labelled transcript separately. If your workflow needs both speaker attribution and PII review, validate separate processing paths before launch.
No. A scan reports what the configured checks found in the supplied transcript. It does not establish legal compliance, prove a disclosure was heard or certify that the recording contains no sensitive information.
Trace is in beta. The recording path requires the organization's Trace entitlement and an explicit trace option on the transcription job. Hear processing and Trace usage are metered separately. Check PyAI pricing and your console for current terms.
Documentation / reviewed September 11, 2026
Independent PyAI integration guidance. No OpenAI partnership or native connector is implied.
Bring your recording format and review requirements. We’ll help you identify the supported Trace path.