Recordings
A recording exists once per recorded meeting. These endpoints list recordings, return their transcript and summaries, create new recordings from uploads or URLs and set their tags.
Every endpoint below shows its parameters and response fields in the middle and a request sample with an example response on the right.
Lists recordings of a directory (paginated, optionally filtered by date)
/v1.0/directories/{directoryId}/recordingsPagination via ?page + ?pageSize (max. 100). Optional ?createdAfter / ?createdBefore are UTC ISO-8601 (YYYY-MM-DDTHH:MM:SSZ, see „Dates & times" above). Sorted by creation date descending.
Field overview from the specification
Response fields:
page/pageSize/total/hasMore: pagination envelope (current page, page size, total count, whether more pages follow).items(array): the recordings on this page. Each item has:recordingId(string): id of the recording.name(string | null): display name of the recording.durationInSeconds(number | null): duration in seconds.isManualUpload(boolean): true if manually uploaded (no meeting bot).isTranscriptionSucceeded(boolean): true when a usable transcript exists. A run that finished without producing one (no spoken audio, empty file, language not detected) leaves this false.isTranscriptionCompleted(boolean): true once the transcription run has finished, whether or not it produced a transcript. Tells "still running" apart from "finished without a result".transcriptionCompletionReason(string enum): why the run ended. One ofsucceeded,noSpokenAudio,fileEmpty,languageNotDetected,error,quotaExceeded,unknown. The underlying error text is deliberately not exposed.languageCode(string | null): language code of the recording (IETF language tag, e.g.de-DE,en-US).createdOn(string): creation timestamp (ISO-8601).tags(array): effective tags (own + inherited from linked appointments and their recurring series master). Each tag has:tagId(string): id of the tag.name(string): tag display name.colorCode(string | null): a colour key from the Sally tag palette (a colour name likeblue/red/green, not a raw hex value; full list in the schema); null if unset.
Path parameters
directoryIdstringrequiredId of the directory (the Sally company account) the resource belongs to. The directories a token can address are listed by
GET /v1.0/me/directories/memberships.
Query parameters
pagenumberoptionalPage number, 1-based. Defaults to 1.
pageSizenumberoptionalItems per page. Defaults to 25, capped at 100.
createdAfterstringoptionalOnly recordings created at/after this UTC ISO-8601 timestamp (
YYYY-MM-DDTHH:MM:SSZ).createdBeforestringoptionalOnly recordings created at/before this UTC ISO-8601 timestamp (
YYYY-MM-DDTHH:MM:SSZ).fieldsstringoptionalComma-separated list of the fields to return. Leave it out and you get every field — including fields added in the future, which is your call to make: name your fields if you want to be shielded from that.
Only first-level fields can be named. A nested list such as
attendees,tagsorsectionItemsis returned whole or not at all;attendees.nameis not supported.On a paged response the selection applies to the entries in
items;page,pageSize,totalandhasMoreare always returned. An unknown name is rejected with 400 rather than ignored.Selectable here:
createdOn,durationInSeconds,isManualUpload,isTranscriptionCompleted,isTranscriptionSucceeded,languageCode,name,recordingId,tags,transcriptionCompletionReason.Example:createdOn,durationInSeconds
Response: each entry in items
recordingIdstringrequiredId of the recording.
namestringrequirednullableDisplay name of the recording.
durationInSecondsnumberrequirednullableDuration in seconds.
isManualUploadbooleanrequiredTrue if manually uploaded (no meeting bot).
isTranscriptionSucceededbooleanrequiredTrue when a usable transcript exists. This is NOT the same as the run having finished: a recording without spoken audio finishes too, and then this stays false.
isTranscriptionCompletedbooleanrequiredTrue once the transcription run has finished, whether or not it produced a transcript. Use this to tell "still running" apart from "finished without a result"; whether there is something to read is
isTranscriptionSucceeded.transcriptionCompletionReasonstringrequiredWhy the transcription run ended.
unknownwhile it has not finished. The underlying error text is deliberately not exposed.Allowed values:succeedednoSpokenAudiofileEmptylanguageNotDetectederrorquotaExceededunknownlanguageCodestringrequirednullableLanguage code of the recording (IETF language tag, e.g.
de-DE,en-US).createdOnstringrequiredCreation timestamp (ISO-8601).
tagsobject[]requiredEffective tags (own + inherited from linked appointments and their recurring series master).
3 child fields
tagIdstringrequiredId of the tag.
namestringrequiredTag display name.
colorCodestringrequirednullableColour of the tag as a key from Sally's fixed tag palette — a colour NAME, not a raw hex value. One of:
indigo,purple,fuchsia,pink,rose,red,orange,amber,yellow,lime,green,emerald,teal,cyan,sky,blue,slate,gray,zinc,stone,neutral. The client maps the key to the actual (light/dark) colour;nullor an unknown key renders in the neutral default colour. Null if unset.
Every page also carries page, pageSize, total, hasMore.
Status codes
- 200Success
- 400
Invalid request (validation error).
- 401
Missing or invalid bearer token.
- 404
Resource not found or not accessible.
- 429
Rate limit exceeded (per token/IP). Transcription uploads may also return
codeFUP_LIMIT_EXCEEDEDorTOO_MANY_CONCURRENT_TRANSCRIPTIONS. - 500
Internal server error.
Returns a single recording
/v1.0/directories/{directoryId}/recordings/{recordingId}Field overview from the specification
Response fields:
recordingId(string): id of the recording.name(string | null): display name of the recording.durationInSeconds(number | null): duration in seconds.isManualUpload(boolean): true if manually uploaded (no meeting bot).isTranscriptionSucceeded(boolean): true when a usable transcript exists. A run that finished without producing one (no spoken audio, empty file, language not detected) leaves this false.isTranscriptionCompleted(boolean): true once the transcription run has finished, whether or not it produced a transcript. Tells "still running" apart from "finished without a result".transcriptionCompletionReason(string enum): why the run ended. One ofsucceeded,noSpokenAudio,fileEmpty,languageNotDetected,error,quotaExceeded,unknown. The underlying error text is deliberately not exposed.languageCode(string | null): language code of the recording (IETF language tag, e.g.de-DE,en-US).createdOn(string): creation timestamp (ISO-8601).tags(array): effective tags (own + inherited from linked appointments and their recurring series master). Each tag has:tagId(string): id of the tag.name(string): tag display name.colorCode(string | null): a colour key from the Sally tag palette (a colour name likeblue/red/green, not a raw hex value; full list in the schema); null if unset.
Path parameters
directoryIdstringrequiredId of the directory (the Sally company account) the resource belongs to. The directories a token can address are listed by
GET /v1.0/me/directories/memberships.recordingIdstringrequiredId of the recording.
Query parameters
fieldsstringoptionalComma-separated list of the fields to return. Leave it out and you get every field — including fields added in the future, which is your call to make: name your fields if you want to be shielded from that.
Only first-level fields can be named. A nested list such as
attendees,tagsorsectionItemsis returned whole or not at all;attendees.nameis not supported.On a paged response the selection applies to the entries in
items;page,pageSize,totalandhasMoreare always returned. An unknown name is rejected with 400 rather than ignored.Selectable here:
createdOn,durationInSeconds,isManualUpload,isTranscriptionCompleted,isTranscriptionSucceeded,languageCode,name,recordingId,tags,transcriptionCompletionReason.Example:createdOn,durationInSeconds
Response
recordingIdstringrequiredId of the recording.
namestringrequirednullableDisplay name of the recording.
durationInSecondsnumberrequirednullableDuration in seconds.
isManualUploadbooleanrequiredTrue if manually uploaded (no meeting bot).
isTranscriptionSucceededbooleanrequiredTrue when a usable transcript exists. This is NOT the same as the run having finished: a recording without spoken audio finishes too, and then this stays false.
isTranscriptionCompletedbooleanrequiredTrue once the transcription run has finished, whether or not it produced a transcript. Use this to tell "still running" apart from "finished without a result"; whether there is something to read is
isTranscriptionSucceeded.transcriptionCompletionReasonstringrequiredWhy the transcription run ended.
unknownwhile it has not finished. The underlying error text is deliberately not exposed.Allowed values:succeedednoSpokenAudiofileEmptylanguageNotDetectederrorquotaExceededunknownlanguageCodestringrequirednullableLanguage code of the recording (IETF language tag, e.g.
de-DE,en-US).createdOnstringrequiredCreation timestamp (ISO-8601).
tagsobject[]requiredEffective tags (own + inherited from linked appointments and their recurring series master).
3 child fields
tagIdstringrequiredId of the tag.
namestringrequiredTag display name.
colorCodestringrequirednullableColour of the tag as a key from Sally's fixed tag palette — a colour NAME, not a raw hex value. One of:
indigo,purple,fuchsia,pink,rose,red,orange,amber,yellow,lime,green,emerald,teal,cyan,sky,blue,slate,gray,zinc,stone,neutral. The client maps the key to the actual (light/dark) colour;nullor an unknown key renders in the neutral default colour. Null if unset.
Status codes
- 200Success
- 400
Invalid request (validation error).
- 401
Missing or invalid bearer token.
- 404
Resource not found or not accessible.
- 429
Rate limit exceeded (per token/IP). Transcription uploads may also return
codeFUP_LIMIT_EXCEEDEDorTOO_MANY_CONCURRENT_TRANSCRIPTIONS. - 500
Internal server error.
Returns the transcript of a recording (time-coded segments + speakers)
/v1.0/directories/{directoryId}/recordings/{recordingId}/transcriptionField overview from the specification
Response fields:
recordingId(string): associated recording id.speakers(array): speakers of the transcript. Each item has:speakerId(string): id of the transcript speaker (referenced by each segment).speakerNumber(number): speaker number.name(string | null): name of the speaker.emailAddress(string | null): email of the speaker.
segments(array): time-coded segments. Each item has:speakerId(string): speaker id of the segment (resolves to thespeakerslist above).startTime(number): start time in seconds.endTime(number): end time in seconds.text(string | null): transcribed text of the segment.
Path parameters
directoryIdstringrequiredId of the directory (the Sally company account) the resource belongs to. The directories a token can address are listed by
GET /v1.0/me/directories/memberships.recordingIdstringrequiredId of the recording.
Query parameters
fieldsstringoptionalComma-separated list of the fields to return. Leave it out and you get every field — including fields added in the future, which is your call to make: name your fields if you want to be shielded from that.
Only first-level fields can be named. A nested list such as
attendees,tagsorsectionItemsis returned whole or not at all;attendees.nameis not supported.On a paged response the selection applies to the entries in
items;page,pageSize,totalandhasMoreare always returned. An unknown name is rejected with 400 rather than ignored.Selectable here:
recordingId,segments,speakers.Example:recordingId,segments
Response
recordingIdstringrequiredAssociated recording id.
speakersobject[]requiredSpeakers of the transcript.
4 child fields
speakerIdstringrequiredId of the transcript speaker.
speakerNumbernumberrequiredSpeaker number.
namestringrequirednullableName of the speaker.
emailAddressstringrequirednullableEmail of the speaker.
segmentsobject[]requiredTime-coded segments.
4 child fields
speakerIdstringrequiredSpeaker id of the segment.
startTimenumberrequiredStart time in seconds.
endTimenumberrequiredEnd time in seconds.
textstringrequirednullableTranscribed text of the segment.
Status codes
- 200Success
- 400
Invalid request (validation error).
- 401
Missing or invalid bearer token.
- 404
Resource not found or not accessible.
- 429
Rate limit exceeded (per token/IP). Transcription uploads may also return
codeFUP_LIMIT_EXCEEDEDorTOO_MANY_CONCURRENT_TRANSCRIPTIONS. - 500
Internal server error.
Returns the summaries of a recording
/v1.0/directories/{directoryId}/recordings/{recordingId}/summariesWith ?includeDetails=true, each summary additionally embeds its section items (the structured per-section results of the meeting template). Without the parameter, only the summary texts. To fetch a single summary by id, use GET .../summaries/{recordingSummaryId}.
Field overview from the specification
Each item has:
recordingSummaryId(string): id of the recording summary.recordingId(string): associated recording id.appointmentId(string | null): associated appointment id (if present).languageCode(string | null): language code of the summary (IETF language tag, e.g.de-DE,en-US).summary(string | null): summary text.isSummarizationCompleted(boolean): true once the summarization run has finished, whether or not it produced anything.isSummarizationSucceeded(boolean): true when there is something to read: summary text or at least one section item. A run over a recording without a transcript finishes too, and then this stays false.summarizationCompletionReason(string enum): why the run ended. One ofsucceeded,noTranscript,emptyResult,error,unknown.noTranscriptis an expected outcome, not a failure. The underlying error text is deliberately not exposed.createdOn(string): creation timestamp (ISO-8601).sectionItems(array | null): the generated section items of the summary (structured per-section results of the meeting template). Null unless loaded (only with?includeDetails=true). Each section item has:sectionItemId(string): id of the section item.meetingTemplateSectionId(string | null): id of the meeting template section this item was generated from (resolve viaGET /v1.0/directories/{directoryId}/meetingtemplates/{meetingTemplateId}); null for derived items (e.g. task items).title(string): title of the template section item.sectionType(string enum): section type of the item. One ofsummary,tasks,topics,decisions,customList,freeText,unknown.outputFormat(string enum): output format of the item content. One ofhtml,markdown,unknown.sortOrder(number): order within the summary.content(string | null): free-text/Markdown content of the item.subject(string | null): task subject (for task-like section items).description(string | null): task description.responsibleUserName(string | null): responsible person (name).responsibleUserEmail(string | null): responsible person (email).dueDate(string | null): due date (ISO-8601).
Path parameters
directoryIdstringrequiredId of the directory (the Sally company account) the resource belongs to. The directories a token can address are listed by
GET /v1.0/me/directories/memberships.recordingIdstringrequiredId of the recording.
Query parameters
includeDetailsbooleanoptionalWhen
true, every summary additionally carries itssectionItems. When omitted orfalse,sectionItemsisnulland only the summary text is returned.fieldsstringoptionalComma-separated list of the fields to return. Leave it out and you get every field — including fields added in the future, which is your call to make: name your fields if you want to be shielded from that.
Only first-level fields can be named. A nested list such as
attendees,tagsorsectionItemsis returned whole or not at all;attendees.nameis not supported.On a paged response the selection applies to the entries in
items;page,pageSize,totalandhasMoreare always returned. An unknown name is rejected with 400 rather than ignored.Selectable here:
appointmentId,createdOn,isSummarizationCompleted,isSummarizationSucceeded,languageCode,recordingId,recordingSummaryId,sectionItems,summarizationCompletionReason,summary.Example:appointmentId,createdOn
Response
recordingSummaryIdstringrequiredId of the recording summary.
recordingIdstringrequiredAssociated recording id.
appointmentIdstringrequirednullableAssociated appointment id (if present).
languageCodestringrequirednullableLanguage code of the summary (IETF language tag, e.g.
de-DE,en-US).summarystringrequirednullableSummary text.
isSummarizationCompletedbooleanrequiredTrue once the summarization run has finished, whether or not it produced anything.
isSummarizationSucceededbooleanrequiredTrue when there is something to read: summary text or at least one section item. A run over a recording without a transcript finishes too, and then this stays false.
summarizationCompletionReasonstringrequiredWhy the summarization run ended.
noTranscriptmeans there was nothing to summarize, which is an expected outcome and not a failure.unknownwhile it has not finished. The underlying error text is deliberately not exposed.Allowed values:succeedednoTranscriptemptyResulterrorunknowncreatedOnstringrequiredCreation timestamp (ISO-8601).
sectionItemsobject[]requirednullableThe generated section items of the summary (the structured, per-section results of the meeting template). Null when not loaded (the recordings list endpoint only fills this with
?includeDetails=true); the single-summary endpoint always includes it.12 child fields
sectionItemIdstringrequiredId of the section item.
meetingTemplateSectionIdstringrequirednullableId of the meeting template section this item was generated from. Resolve it via
GET /v1.0/directories/{directoryId}/meetingtemplates/{meetingTemplateId}(matches a section’smeetingTemplateSectionId). Null for derived items without a template section (e.g. task items).titlestringrequiredTitle of the template section item.
sectionTypestringrequiredSection type of the item.
Allowed values:summarytaskstopicsdecisionscustomListfreeTextunknownoutputFormatstringrequiredOutput format of the item content.
Allowed values:htmlmarkdownunknownsortOrdernumberrequiredOrder within the summary.
contentstringrequirednullableFree-text/Markdown content of the item.
subjectstringrequirednullableTask subject (for task-like section items).
descriptionstringrequirednullableTask description.
responsibleUserNamestringrequirednullableResponsible person (name).
responsibleUserEmailstringrequirednullableResponsible person (email).
dueDatestringrequirednullableDue date (ISO-8601).
Status codes
- 200Success
- 400
Invalid request (validation error).
- 401
Missing or invalid bearer token.
- 404
Resource not found or not accessible.
- 429
Rate limit exceeded (per token/IP). Transcription uploads may also return
codeFUP_LIMIT_EXCEEDEDorTOO_MANY_CONCURRENT_TRANSCRIPTIONS. - 500
Internal server error.
Starts a recording upload (step 1/2) — returns a SAS PUT URL
/v1.0/directories/{directoryId}/recordings/uploadsThe client then uploads the file bytes via PUT directly to the returned uploadUrl (with the requiredHeaders) and afterwards calls POST .../uploads/{uploadId}/finalize. The transcription quota (fair usage policy) is already checked here — if the quota is exhausted, 429 with code FUP_LIMIT_EXCEEDED is returned.
Field overview from the specification
Body fields:
fileName(string, required): original file name (incl. extension, for MIME/extension derivation).mimeType(string, required): MIME type of the file (whitelist: video mp4/mkv/avi/mov/webm, audio mp3/wav/flac/ogg/amr/m4a/opus/aac).sizeBytes(number, required): file size in bytes (> 0, max. 5 GB).
Path parameters
directoryIdstringrequiredId of the directory (the Sally company account) the resource belongs to. The directories a token can address are listed by
GET /v1.0/me/directories/memberships.
Query parameters
fieldsstringoptionalComma-separated list of the fields to return. Leave it out and you get every field — including fields added in the future, which is your call to make: name your fields if you want to be shielded from that.
Only first-level fields can be named. A nested list such as
attendees,tagsorsectionItemsis returned whole or not at all;attendees.nameis not supported.On a paged response the selection applies to the entries in
items;page,pageSize,totalandhasMoreare always returned. An unknown name is rejected with 400 rather than ignored.Selectable here:
maxBytes,requiredHeaders,storageMode,uploadId,uploadUrl.Example:maxBytes,requiredHeaders
Request body application/json
fileNamestringrequiredOriginal file name (incl. extension, for MIME/extension derivation).
mimeTypestringrequiredMIME type of the file (whitelist: video mp4/mkv/avi/mov/webm, audio mp3/wav/flac/ogg/amr/m4a/opus/aac).
Example:audio/mpegsizeBytesnumberrequiredFile size in bytes (> 0, max. 5 GB).
Response
uploadIdstringrequiredUpload token — passed along in the finalize step.
uploadUrlstringrequiredAbsolute Azure SAS URL. The client uploads the file bytes via
PUTdirectly to it (no API roundtrip).storageModestringrequiredStorage mode.
Example:azure-blobrequiredHeadersobjectrequiredHeaders that must be sent with the
PUT.Example:{"x-ms-blob-type":"BlockBlob"}maxBytesnumberrequiredMaximum allowed upload size in bytes.
Status codes
- 200Success
- 400
Invalid request (validation error).
- 401
Missing or invalid bearer token.
- 403
Forbidden (insufficient permissions).
- 404
Resource not found or not accessible.
- 429
Rate limit exceeded (per token/IP). Transcription uploads may also return
codeFUP_LIMIT_EXCEEDEDorTOO_MANY_CONCURRENT_TRANSCRIPTIONS. - 500
Internal server error.
Completes a recording upload (step 2/2) — creates the recording
/v1.0/directories/{directoryId}/recordings/uploads/{uploadId}/finalizeCall after a successful PUT of the file bytes. Verifies the blob, creates the recording row and triggers the transcription pipeline. Returns the recordingId. If too many transcriptions of the directory are running concurrently, 429 with code TOO_MANY_CONCURRENT_TRANSCRIPTIONS is returned.
Field overview from the specification
Body fields (all optional):
languageCode(string, optional): language code of the audio (IETF language tag, e.g.de-DE,en-US). Omit or null to auto-detect.speakerCount(number, optional): number of speakers (for diarization).appointmentId(string, optional): optionally linked appointment (GUID).
Path parameters
directoryIdstringrequiredId of the directory (the Sally company account) the resource belongs to. The directories a token can address are listed by
GET /v1.0/me/directories/memberships.uploadIdstringrequiredId of the upload.
Query parameters
fieldsstringoptionalComma-separated list of the fields to return. Leave it out and you get every field — including fields added in the future, which is your call to make: name your fields if you want to be shielded from that.
Only first-level fields can be named. A nested list such as
attendees,tagsorsectionItemsis returned whole or not at all;attendees.nameis not supported.On a paged response the selection applies to the entries in
items;page,pageSize,totalandhasMoreare always returned. An unknown name is rejected with 400 rather than ignored.Selectable here:
recordingId.Example:recordingId
Request body application/json
languageCodestringoptionalnullableLanguage code of the audio (IETF language tag, e.g.
de-DE,en-US). Omit or null to auto-detect.speakerCountnumberoptionalnullableNumber of speakers (for diarization).
appointmentIdstringoptionalnullableOptionally linked appointment (GUID).
Response
recordingIdstringrequiredId of the created recording (transcription has been triggered).
Status codes
- 200Success
- 400
Invalid request (validation error).
- 401
Missing or invalid bearer token.
- 403
Forbidden (insufficient permissions).
- 404
Resource not found or not accessible.
- 429
Rate limit exceeded (per token/IP). Transcription uploads may also return
codeFUP_LIMIT_EXCEEDEDorTOO_MANY_CONCURRENT_TRANSCRIPTIONS. - 500
Internal server error.
Creates a recording from a file URL (no upload needed)
/v1.0/directories/{directoryId}/recordings/from-urlSally fetches the file from the URL server-side, stores it and triggers the transcription and summarization pipeline, exactly like a finished upload. Use this instead of the two-step upload when the file is already reachable over https. The call returns once the file has been fetched and the recording exists; transcription then runs in the background, so poll GET .../recordings/{recordingId} or use a webhook for the result.
Field overview from the specification
What the URL must satisfy (each of these is enforced, and a violation returns 400):
httpsonly. Nohttp, no other scheme.- No credentials in the URL. A
user:pass@hostform is rejected. - Public targets only. The host is resolved and rejected if it points into a private or reserved network (loopback, private ranges, link-local including cloud metadata, CGNAT, multicast). The verified address is then pinned for the connection, so a DNS answer that changes between check and fetch cannot redirect us inside.
- No redirects. Pass the final address; a redirect is rejected rather than followed.
- A supported media type, either by
Content-Typeor by the file extension:mp4,mkv,avi,mov,webm,mp3,wav,flac,ogg,amr,m4a,opus,aac. - Size limit as returned by the upload endpoint (
maxBytes). Both the declaredContent-Lengthand the actual bytes are checked.
The same licence, trial and fair-usage rules apply as for an upload. If too many transcriptions of the directory are running concurrently, 429 with code TOO_MANY_CONCURRENT_TRANSCRIPTIONS is returned and nothing is fetched.
Body fields:
url(string): the https URL of the file.name(string, optional): name of the recording. The URL is never used as the name, because presigned links carry credentials in their query string.languageCode(string, optional): IETF language tag of the audio, e.g.de-DE. Omit to auto-detect.speakerCount(number, optional): number of speakers, for diarization.
Path parameters
directoryIdstringrequiredId of the directory (the Sally company account) the resource belongs to. The directories a token can address are listed by
GET /v1.0/me/directories/memberships.
Query parameters
fieldsstringoptionalComma-separated list of the fields to return. Leave it out and you get every field — including fields added in the future, which is your call to make: name your fields if you want to be shielded from that.
Only first-level fields can be named. A nested list such as
attendees,tagsorsectionItemsis returned whole or not at all;attendees.nameis not supported.On a paged response the selection applies to the entries in
items;page,pageSize,totalandhasMoreare always returned. An unknown name is rejected with 400 rather than ignored.Selectable here:
recordingId.Example:recordingId
Request body application/json
urlstringrequiredPublicly reachable https URL of the audio or video file. Must point to the file itself, not to a landing page or a redirect. Presigned links (S3, Azure Blob, Google Cloud Storage) work as long as they are valid at the time of the call.
namestringoptionalnullableName of the recording. Defaults to a generated name if omitted; the URL is never used as the name, since presigned links carry credentials in their query string.
languageCodestringoptionalnullableLanguage code of the audio (IETF language tag, e.g.
de-DE,en-US). Omit or null to auto-detect.speakerCountnumberoptionalnullableNumber of speakers (for diarization).
Response
recordingIdstringrequiredId of the created recording (transcription has been triggered).
Status codes
- 200Success
- 400
Invalid request (validation error).
- 401
Missing or invalid bearer token.
- 403
Forbidden (insufficient permissions).
- 404
Resource not found or not accessible.
- 429
Rate limit exceeded (per token/IP). Transcription uploads may also return
codeFUP_LIMIT_EXCEEDEDorTOO_MANY_CONCURRENT_TRANSCRIPTIONS. - 500
Internal server error.
Replaces the direct tags of a recording (assign/unassign)
/v1.0/directories/{directoryId}/recordings/{recordingId}/tagsReplace-set of the recording’s DIRECT tags; tags inherited from linked appointments/series stay dynamic. Max. 20 direct tags per recording.
Field overview from the specification
Body fields:
tagIds(array of strings): existing tag ids to assign; the given set replaces the current one. Assigning only takes tag ids, so create the tag first viaPOST /v1.0/directories/{directoryId}/tagsand assign it here.
Path parameters
directoryIdstringrequiredId of the directory (the Sally company account) the resource belongs to. The directories a token can address are listed by
GET /v1.0/me/directories/memberships.recordingIdstringrequiredId of the recording.
Query parameters
fieldsstringoptionalComma-separated list of the fields to return. Leave it out and you get every field — including fields added in the future, which is your call to make: name your fields if you want to be shielded from that.
Only first-level fields can be named. A nested list such as
attendees,tagsorsectionItemsis returned whole or not at all;attendees.nameis not supported.On a paged response the selection applies to the entries in
items;page,pageSize,totalandhasMoreare always returned. An unknown name is rejected with 400 rather than ignored.Selectable here:
colorCode,name,tagId.Example:colorCode,name
Request body application/json
tagIdsstring[]optionalExisting tag ids to assign; the given set replaces the current one.
Response
tagIdstringrequiredId of the tag.
namestringrequiredTag display name.
colorCodestringrequirednullableColour of the tag as a key from Sally's fixed tag palette — a colour NAME, not a raw hex value. One of:
indigo,purple,fuchsia,pink,rose,red,orange,amber,yellow,lime,green,emerald,teal,cyan,sky,blue,slate,gray,zinc,stone,neutral. The client maps the key to the actual (light/dark) colour;nullor an unknown key renders in the neutral default colour. Null if unset.
Status codes
- 200Success
- 400
Invalid request (validation error).
- 401
Missing or invalid bearer token.
- 403
Forbidden (insufficient permissions).
- 404
Resource not found or not accessible.
- 429
Rate limit exceeded (per token/IP). Transcription uploads may also return
codeFUP_LIMIT_EXCEEDEDorTOO_MANY_CONCURRENT_TRANSCRIPTIONS. - 500
Internal server error.