Skip to main content
Version: Next — unreleased

Recording output reference

Use this reference to interpret recording objects and investigate missing output. Recording is a shared Delphi capability. This reference describes the common fields that Delphi writes; it is not an exhaustive JSON schema. Integration-specific metadata and application-defined nested values may also be present; use your assigned integration reference for their exact contract.

Artifact selection, processing and successful storage are separate conditions. A selected output is not evidence that its object exists. A stored processing status is a snapshot, not a live status endpoint.

Availability: Your application must select the relevant recording outputs, and your team must have a configured, accessible recording destination. To read the objects in the bucket, you need access in your storage account; a Delphi team role does not grant it. Optional integration metadata can be null even when its field is present.

To choose outputs, use recording selection. To configure the destination and retention, use team recording storage. For an end-to-end investigation, use recording diagnostics.

File roles and creation conditions​

ArtifactWriterCondition / limit
call-transcript.jsonTelPhi recording uploaderSelected independently by the recording output plan; upload failure is caught/logged, so selection does not guarantee an object
transcript-stt-input.jsonTasker audio-recording processorSTT transcript output selected and, from 0.9.18, at least one caller turn activity
transcript-tts-output.jsonSame Tasker processorTTS transcript output selected and, from 0.9.18, at least one bot turn activity
recording-processed.mp3Same Tasker processorProcessed MP3 output selected and a post-audioproc caller stage exists; bot audio makes this a stereo mix
recording-raw.mp3Same Tasker processorRaw MP3 output selected, and either a pre-audioproc caller stage exists or the input has outbound audio only

From 0.9.18, Delphi omits an empty turn transcript: when the call had activity only on the other side, the side-specific document is not written. In 0.9.17-patch2 and earlier, it was written with empty items.

Delphi writes no standalone .txt transcript. Other subsystems may produce additional files.

A completed recording job can legitimately upload only recording-raw.mp3 when its input stages are pre-audioproc and outbound. Check the job's stage list before treating the missing processed file as a processing failure. A logged S3 upload is useful correlation evidence; verify the current object separately.

From 0.9.18, newly stored recordings use the date-partitioned prefix recordings/{teamId}/{appId}/{YYYY}/{MM}/{DD}/{folder}. The date folders use the UTC call-start date, with zero-padded month and day. folder combines the formatted start timestamp, sanitized conversation ID and optional customer integration ID. For example, a call starting on 17 June 2026 can use recordings/team-1/app-1/2026/06/17/2026-06-17T13-09-51_conversation-1/. Identifier sanitization replaces disallowed characters and truncates to 160 characters. Missing start time uses the current time. Failed or missing conversation lookup still uses a flat legacy call-ID prefix. Recordings from 0.9.17-patch2 and earlier may use a flat timestamped prefix. Playback, listing and deletion search the new and older layouts. Consumers should use recorded object keys, not reconstruct them from this description.

Call document fields​

FieldMeaning / condition
schemaVersionLiteral 1
generatedAtISO timestamp when the document is built
storageProtection.sensitiveInfoOnStorageObservedWhether the recorder observed sensitive-storage redaction
storageProtection.storageRedacted, .redactionReasonPresent for protected storage; true and sensitiveInfoOnStorage
call.conversationId, .callIdConversation-row IDs with channel/call input fallbacks
call.traceIdConversation trace identifier or null
call.teamId, .appIdRecording configuration team; conversation app with configuration fallback
call.callerNumberIn-memory PII snapshot when supplied, otherwise conversation value/null
call.endReasonFrom 0.9.18, resolved detail after final hangup; null if unavailable or captured during a resumable pause
call.startTime, .endTimeISO timestamp from recorded milliseconds, or null
call.durationSecondsRecorded duration, otherwise computed from available start/end times, otherwise null
call.flowDefinitionId, .flowVersionConversation flow identifiers/version, or null
recording.bucket, .regionSelected recording destination values
recording.s3Prefix, .transcriptS3KeyActual prefix and full call-document key
recording.recordingStatusSnapshot: PROCESSING when stages are present, otherwise conversation status/null; not a live processing status
recording.recordingFileConversation recording-file value/null at serialization time
recording.stagesUploaded stage descriptors supplied to the writer; empty when call JSON is written without persisted audio stages
transcriptSanitized transcript combined with recorded DTMF entries and sorted by timestamp
dtmfEventsDTMF sidecar array; field details below
nodeHistory, actionsLog, finalContext, systemContextRuntime data with additional sensitive-storage sanitization; not fixed complete object schemas here

Stage descriptor fields are stage, s3Key, codec, sampleRate, bitDepth, channels, byteCount and optional segments. Segment fields declared by the writer type are startMs, byteOffset, byteLength, optional endMs, durationMs, turnId, side, transcript, timestamp, provider, model, storageRedacted and redactionReason. Optional/undefined members are not guaranteed JSON keys. These descriptors identify the uploaded stages; their presence alone does not verify media duration, channel layout or successful playback.

BigInts anywhere in this call payload serialize as strings. Runtime transcript, context, node and action values may contain arbitrary application data. Their nested shape depends on the application; the field list below does not define a closed schema for those runtime values.

Turn document and item fields​

Both turn documents emit schemaVersion: 1, generatedAt, call and items. The common call fields are conversationId and callId; integration metadata may also be present. The STT file keeps client-side items; the TTS file keeps bot-side items. From 0.9.18, a side's file is omitted when that side has no turn activity. Protected turns remain as redacted items even when their text and audio references are empty.

Item fieldMeaning / condition
turnIdNonblank segment turn-ID string, preserved unchanged, or null
sideDisplay value Client or Bot
speakerLowercase side client or bot
timestampSegment timestamp, matching transcript ts/timestamp, or call-start plus segment offset; may be null
startMsSegment start offset
endMsFinite segment end, otherwise start plus available activity duration, otherwise null
durationMsActivity duration; may be null
textSegment transcript with matched transcript fallback; null for protected storage
audioMap of formats to relative object paths; may be empty
s3AudioMap of formats to full S3 object keys; may be empty
mediaFormatActivity media format
provider, modelSegment metadata or null
stageActivity stage
nodeIdNonblank node-ID string from the matched transcript entry, preserved unchanged, or null
storageRedacted, redactionReasonAdded for protected items; true and the segment reason/fallback sensitiveInfoOnStorage

Items are sorted by timestamp when both timestamps exist, otherwise by startMs. Matching transcript fallback is sequential within each user/assistant role; do not describe it as a verified semantic alignment of transcript and audio. The processor supports raw/MP3 format outputs, but maps and actual objects depend on selection and successful processing. A URL or object existence is not implied by a JSON key.

Redaction and DTMF boundaries​

From 0.9.19, new calls start with the App's explicit protection choice or inherit the platform default. Configure and verify the initial value through Starting storage protection.

Protection changes what selected outputs retain. It does not select recording outputs, delete previously stored objects or turn application logging off.

Protected outputRetained result
Full call transcriptActivities remain with redacted text and storageRedacted: true, redactionReason: "sensitiveInfoOnStorage".
STT/TTS turn transcriptsItems remain with text: null and protection markers; protected audio snippets are not stored.
Full call audioProtected audio is replaced with equal-length silence, preserving the recording timeline. There is no generated redaction beep.

Output selection and successful processing/storage remain separate requirements.

DTMF sidecars emit digit, startMs, durationMs, timestamp. Protected events replace digit with null and add storageRedacted: true and the redaction reason. startMs is the offset in milliseconds from when the call recorder started, or from the call channel's start when no audio recorder runs. durationMs is the keypress duration reported by telephony; when none is reported, Delphi stores 200. timestamp is the ISO 8601 UTC time of the key press. Repeated presses of the same digit less than 80 ms apart are stored once. An unprotected event looks like this:

{"digit": "1", "startMs": 12037, "durationMs": 260, "timestamp": "2026-09-16T06:11:55.211Z"}

From 0.9.18, dtmfEvents can also contain collector-beep entries with kind: "beep", an empty digit (null when protected) and durationMs: 368.5. Delphi adds one after it plays the keypad start tone: when keypad input collection starts, and to the caller when an attended transfer connects. Beep entries do not appear in transcript. Count only entries without kind as key presses.

The transcript's DTMF entry uses nodeId: dtmf, role: user, source: dtmf, ts and text DTMF <digit> or [Redacted], with protection markers when applicable.

Marked transcript entries are re-sanitized even when an in-memory PII snapshot is used. For a protected call, context fields become redaction markers. Node history retains selected structural/timing/usage fields, with transition/error payloads marked; action entries retain selected structural identifiers and markers. This is not a claim that every field in the entire call document is anonymized.

Logging PII controls must not be equated with storage redaction: the writer can prefer an in-memory caller/transcript snapshot when the database row is redacted. For Timeline, Debug logs and trace output, verify diagnostic-log protection separately. A masked UI value alone does not prove that a stored recording was protected. This behavior is not a compliance or data-retention guarantee.

Investigate a missing or unexpected transcript​

  1. Identify the conversation, product version and selected output artifact. Check the exact object key recorded for that conversation rather than reconstructing a prefix from its identifiers.
  2. For call-transcript.json, inspect the recording uploader's result and errors. For either turn transcript, also check processing results and whether that side had turn activity. A call with only bot turns has no STT turn document.
  3. If the JSON exists but audio cannot be fetched, distinguish an empty audio map, a missing object and denied storage access. A key in JSON is not a signed URL or proof of object existence.
  4. If text or DTMF is redacted, inspect the associated storage-protection markers. Changing a logging option does not restore redacted stored content.
  5. Preserve the conversation identifier, artifact key, product version and sanitized error details for investigation. Do not include production transcript text, credentials or caller numbers in a support example.

Delivery latency, retention and media interoperability depend on your storage destination.