Capturia measures its ads and site traffic with the Meta pixel and Google Analytics. You can decline at any time. Learn more

FR

Conversation imports

3 endpoints

get/v1/conversation-imports

Read the state of a sent conversation

The state of a submission to POST /v1/conversation-imports: received on its contact, waiting for a contact, refused with its reason, or received as a duplicate, and where the analysis of its meeting stands (recording.analysis).

A submission from another account returns 404, like a submission that doesn't exist. A refused or duplicate submission is erased after 30 days; a received submission goes away with its meeting.

Required scopes: conversations:import

Query parameters

NameTypeRequiredDescription
idstringrequiredThe submission's ID, as returned by POST /v1/conversation-imports (id). Missing or malformed, the request returns 400 validation_error.

Responses

StatusDescription
200

State of the submission.

400

Invalid request. code tells apart the refusals the operation returns under this status, and each example shows one.

validation_errorid · required
{
  "error": {
    "type": "validation_error",
    "code": "validation_error",
    "message": "Request validation failed.",
    "hint": "`details` names each field to fix and the reason it was refused.",
    "doc_url": "https://capturia.io/en/developers/api/v1/errors#validation_error",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7",
    "details": [
      {
        "field": "id",
        "reason": "required"
      }
    ]
  }
}
validation_errorid · invalid_uuid
{
  "error": {
    "type": "validation_error",
    "code": "validation_error",
    "message": "Request validation failed.",
    "hint": "`details` names each field to fix and the reason it was refused.",
    "doc_url": "https://capturia.io/en/developers/api/v1/errors#validation_error",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7",
    "details": [
      {
        "field": "id",
        "reason": "invalid_uuid"
      }
    ]
  }
}
401

The API key is missing, unknown or expired. code tells the three causes apart: missing_api_key (no Authorization: Bearer header), invalid_api_key (unknown or revoked key, or invalid format) and expired_api_key (expiration date has passed).

missing_api_key
{
  "error": {
    "type": "authentication_error",
    "code": "missing_api_key",
    "message": "No API key was provided.",
    "hint": "Add an Authorization header in the form: Bearer cap_live_<your_key>",
    "doc_url": "https://capturia.io/en/developers/api/v1/authentication#missing_api_key",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7"
  }
}
invalid_api_key
{
  "error": {
    "type": "authentication_error",
    "code": "invalid_api_key",
    "message": "API key is invalid or has been revoked.",
    "hint": "Verify the key in your dashboard or generate a new one.",
    "doc_url": "https://capturia.io/en/developers/api/v1/authentication#invalid_api_key",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7"
  }
}
expired_api_key
{
  "error": {
    "type": "authentication_error",
    "code": "expired_api_key",
    "message": "API key has expired.",
    "hint": "Roll the key from the dashboard to generate a new valid one.",
    "doc_url": "https://capturia.io/en/developers/api/v1/authentication#expired_api_key",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7"
  }
}
403

Authorization refused. code tells apart the refusals the operation returns under this status, and each example shows one.

browser_not_allowed
{
  "error": {
    "type": "authorization_error",
    "code": "browser_not_allowed",
    "message": "API keys must be used from a server, never from a browser.",
    "hint": "The request carries an `Origin` header: call the API from your server, where the key stays secret.",
    "doc_url": "https://capturia.io/en/developers/api/v1/errors#browser_not_allowed",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7"
  }
}
account_suspended
{
  "error": {
    "type": "authorization_error",
    "code": "account_suspended",
    "message": "Access to this account is suspended by the Capturia team.",
    "hint": "The refusal comes from the account, not the key. While the suspension lasts, no request is accepted: contact the Capturia team.",
    "doc_url": "https://capturia.io/en/developers/api/v1/authentication#account_suspended",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7"
  }
}
feature_not_available
{
  "error": {
    "type": "authorization_error",
    "code": "feature_not_available",
    "message": "This feature is not included in your plan.",
    "hint": "The rejection comes from the account's plan, not the key. Contact your Capturia advisor to talk it over.",
    "doc_url": "https://capturia.io/en/developers/api/v1/authentication#plan",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7",
    "details": {
      "feature": "public_api"
    }
  }
}
insufficient_scope
{
  "error": {
    "type": "authorization_error",
    "code": "insufficient_scope",
    "message": "This API key does not contain the required scope for this endpoint.",
    "hint": "This key is missing the `conversations:import` scope. Create a new key with the \"Read + write\" preset or add the scope via the dashboard.",
    "doc_url": "https://capturia.io/en/developers/api/v1/authentication#scopes",
    "dashboard_url": "https://capturia.io/platform/dashboard/admin/integrations/api-keys/6f1e2d3c-4b5a-4c6d-8e7f-9a0b1c2d3e4f?tab=permissions",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7",
    "details": {
      "required_scope": "conversations:import",
      "required_permission": "call_review.manage",
      "current_scopes": [
        "leads:capture"
      ],
      "suggested_preset": "read_write"
    }
  }
}
404

resource_not_found: no submission on this account has this ID.

resource_not_found
{
  "error": {
    "type": "not_found_error",
    "code": "resource_not_found",
    "message": "The requested resource was not found.",
    "hint": "Verify the resource ID. It may have been deleted or never existed.",
    "doc_url": "https://capturia.io/en/developers/api/v1/errors#resource_not_found",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7"
  }
}
429

Rate limit reached. rate_limit_exceeded: the key's hourly quota is used up. too_many_attempts: too many invalid keys presented from this IP address (brute-force protection). In both cases, Retry-After gives the delay in seconds.

rate_limit_exceeded
{
  "error": {
    "type": "rate_limit_error",
    "code": "rate_limit_exceeded",
    "message": "Rate limit exceeded.",
    "hint": "Retry after the number of seconds in retry_after_seconds, and consider implementing exponential backoff.",
    "doc_url": "https://capturia.io/en/developers/api/v1/rate-limits",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7",
    "details": {
      "limit": 100,
      "count": 100,
      "limit_type": "per_key",
      "retry_after_seconds": 42
    }
  }
}
too_many_attempts
{
  "error": {
    "type": "rate_limit_error",
    "code": "too_many_attempts",
    "message": "Too many invalid authentication attempts from this IP.",
    "hint": "Wait the period indicated by retry_after_seconds before trying again.",
    "doc_url": "https://capturia.io/en/developers/api/v1/authentication#brute-force",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7",
    "details": {
      "limit_type": "brute_force",
      "retry_after_seconds": 300
    }
  }
}
500

Unexpected server error. Always include the request_id when contacting support.

internal_error
{
  "error": {
    "type": "server_error",
    "code": "internal_error",
    "message": "Server error. The Capturia team has been notified.",
    "hint": "If this persists, contact support and include the request_id from this response.",
    "doc_url": "https://capturia.io/en/developers/api/v1/errors#internal_error",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7"
  }
}
501

Test keys (cap_test_) aren't served yet: only cap_live_ keys are accepted.

not_implemented
{
  "error": {
    "type": "server_error",
    "code": "not_implemented",
    "message": "This feature is not yet implemented.",
    "hint": "Check the API documentation for available features and the changelog for upcoming releases.",
    "doc_url": "https://capturia.io/en/developers/api/v1/errors#not_implemented",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7"
  }
}
503

A service the request depends on didn't respond (reading the key, the account or the plan). The same request will go through once it's back: retry after the Retry-After delay.

service_unavailable
{
  "error": {
    "type": "server_error",
    "code": "service_unavailable",
    "message": "Service temporarily unavailable.",
    "hint": "Retry after the period indicated by Retry-After.",
    "doc_url": "https://capturia.io/en/developers/api/v1/errors#service_unavailable",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7"
  }
}

Example request

curl -X GET 'https://api.capturia.io/v1/conversation-imports?id=4e5f6a7b-8c9d-4e0f-9a1b-2c3d4e5f6a7b' \
  -H 'Authorization: Bearer cap_live_<your-key>' \
  -H 'Content-Type: application/json'
post/v1/conversation-imports

Send a conversation held outside Capturia

A call agency, a tool such as Zapier or Make, or your own system sends a conversation held outside Capturia: a call, a video or in-person meeting. Capturia files it on the person's contact and analyzes it like a meeting recorded in Capturia.

As text

Send the transcript as is in transcript.text: Capturia reads it like a text pasted in the app. A "Name: text" line opens a speaking turn; a WebVTT or SRT file is read too. Or send the turns already split in transcript.turns. speakers gives each voice its role by its name (agent, prospect or other); without it, the analysis works out who is speaking. The conversation goes to analysis as soon as the response is sent.

As audio, in three steps

  1. Announce the file in media: its name, its type and its exact size in bytes. The response returns an upload link in upload, valid for 2 hours.
  2. Upload the file with PUT to upload.url, with the Content-Type header of the announced type.
  3. Call POST /v1/conversation-imports/complete with the submission's id: Capturia checks the file, then has it transcribed and analyzed.

Sending the same announcement again before the file arrives returns a new upload link. An audio whose file hasn't arrived one day after its announcement is removed.

Recording notice

recording_notice: "given" declares that every person in the conversation was told it is recorded and analyzed by artificial intelligence; without this declaration, the submission is refused (422 recording_notice_required). The account's management must also have signed the attestation for conversations sent by a provider, in Administration › Imported conversations (422 import_attestation_missing otherwise).

Who held the conversation

Name them in held_by, in seller, or in both. held_by: someone outside the account, for example an agent at a call agency. Their conversation gets its analysis, its summary and its plan, never a score or coaching. seller: the account member responsible for the conversation. Without seller, the conversation goes to the contact's seller, otherwise to the account's default seller.

The contact

contact.id points to the contact; without it, Capturia looks it up by external_id, then phone, then email. An unknown person gets a contact, created without any communication consent (contact_created: true). With create_if_missing: false, or without a phone number or email, the conversation waits for an account member to attach it to a contact (status: awaiting_contact). A contact whose person refused to be recorded receives no conversation (422 contact_refused_recording).

Duplicates

A conversation comes in only once per account. A text with the same words (voice names and timestamps aside), an audio announced identically for the same person (same file name, same size, same occurred_at), or the same external_id under the same external_source returns 200 already_received with the ID of the first submission, without creating a new meeting. An audio therefore always says which conversation it is: external_id, the most reliable match, or occurred_at (media_identity_required with neither). The Idempotency-Key header remains available for retries of a transcript; an audio announcement doesn't read it, so that its retry always returns a fresh upload link.

Limit and cost

Each account receives a limited number of conversations per day (UTC): beyond it, 429 import_daily_limit_reached until the next day. Audio has its own limit, 40 transcribed hours per day (UTC): it is checked at transcription, once the file is received. A file must fit in what remains, based on the measured duration of the audio already transcribed that day and a high estimate of its own, drawn from its size. An audio that doesn't fit is removed; GET /v1/conversation-imports?id= then shows it refused with audio_daily_limit_reached. The analysis is debited from the account's credits, like that of a meeting recorded in Capturia.

Required scopes: conversations:import

Headers

NameTypeRequiredDescription
Idempotency-KeystringoptionalIdempotency key: 16 to 128 [A-Za-z0-9_-] characters (a UUID v4 or a ULID works). A key of any other shape is refused with 400 invalid_request (details.field: idempotency-key); an empty header counts as a request without a key. A second request with the same key and the same payload returns the original response, with the Idempotency-Replayed: true header, without repeating the operation; the same key with a different payload is refused with 409 idempotency_conflict. Stored for 24 h. Optional but recommended.

Request body

PropertyTypeRequiredDescription
transcriptConversationImportTranscriptoptionalThe conversation as text: text or turns, never both (details[].reason: text_or_turns). At least 15 words (422 transcript_too_short), at most 500,000 characters in total.
mediaConversationImportMediaoptionalThe announced audio recording. Its file is then uploaded to the link returned in upload, then POST /v1/conversation-imports/complete has it transcribed and analyzed.
contactConversationImportContactoptionalThe person the conversation was held with. id points to their contact (unknown: 404 contact_not_found); without id, Capturia looks it up by external_id, then phone, then email. A merged contact leads to the contact that was kept. An unknown person gets a contact, created without any communication consent. With create_if_missing: false, or without a phone number or email, the conversation waits for an account member to attach it to a contact (status: awaiting_contact).
recording_noticestringrequiredgiven: every person in the conversation was told it is recorded and analyzed by artificial intelligence. Any other value, or its absence, refuses the submission (422 recording_notice_required).
speakersobjectoptionalThe role of each voice in a transcript, by the name it carries there: agent (the person who held the conversation), prospect or other. 20 voices at most. A name missing from the transcript is ignored. A voice that speakers doesn't name is worked out by the analysis, which keeps the roles given for the others; without speakers, it works out every voice.
held_byobjectoptionalThe person outside the account who held the conversation, for example an agent at a call agency. Their conversation gets its analysis, its summary and its plan, never a score or coaching: they aren't part of the account's team.
sellerobjectoptionalThe account member responsible for the conversation, by id or by email; with both, id wins. An unknown or inactive member refuses the submission (422 seller_not_found). Without seller, the conversation goes to the contact's seller, otherwise to the account's default seller.
meeting_type_idstringoptionalThe meeting type of the conversation. Without it, the account's default type. An unknown or removed type refuses the submission (422 meeting_type_not_found).
occurred_atstringoptionalWhen the conversation took place, with its time zone (Z or an offset).
duration_secondsintegeroptionalDuration of a conversation sent as text, in seconds. Without it, the duration is read from the end of its last timed turn, otherwise estimated from its word count. Ignored for an audio, whose duration is measured at its transcription.
languagestringoptionalLanguage of the conversation, as a two-letter code, with or without its region (fr, en, fr-CA).
titlestringoptionalTitle of the meeting in Capturia.
channelstringoptionalHow the conversation was held: phone (on the phone), video (on video) or in_person (in person). A phone conversation follows the minimum analysis duration of calls, not that of meetings.
external_idstringoptionalThe conversation's ID on the sender's side. A submission with the same external_id and the same external_source is recognized: 200 already_received, no meeting is created a second time.
external_sourcestringoptionalNamespace of external_id (e.g. appels-pro). Default: api.
source_labelstringoptionalName of the source, shown to the account with each submission (e.g. "Appels Pro").

Responses

StatusDescription
200

Conversation already received: the response returns the ID of its first submission, without creating a new meeting.

201

Conversation received. A transcript goes to analysis; an audio waits for its file at the upload link.

400

Invalid request. code tells apart the refusals the operation returns under this status, and each example shows one.

invalid_request
{
  "error": {
    "type": "validation_error",
    "code": "invalid_request",
    "message": "Request format is invalid.",
    "hint": "Check that headers, body and JSON encoding match the API contract documented in the API Reference.",
    "doc_url": "https://capturia.io/en/developers/api/v1/errors#invalid_request",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7"
  }
}
invalid_encoding
{
  "error": {
    "type": "validation_error",
    "code": "invalid_encoding",
    "message": "Request encoding must be UTF-8.",
    "hint": "Use Content-Type: application/json; charset=utf-8.",
    "doc_url": "https://capturia.io/en/developers/api/v1/conventions#encoding",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7"
  }
}
invalid_payload
{
  "error": {
    "type": "validation_error",
    "code": "invalid_payload",
    "message": "The request content is invalid.",
    "hint": "With `details`, each refused field is named with its reason. Without `details`, the body could not be parsed as JSON.",
    "doc_url": "https://capturia.io/en/developers/api/v1/errors#invalid_payload",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7"
  }
}
invalid_requestidempotency-key · invalid_format
{
  "error": {
    "type": "validation_error",
    "code": "invalid_request",
    "message": "Request format is invalid.",
    "hint": "Check that headers, body and JSON encoding match the API contract documented in the API Reference.",
    "doc_url": "https://capturia.io/en/developers/api/v1/errors#invalid_request",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7",
    "details": {
      "field": "idempotency-key",
      "reason": "invalid_format"
    }
  }
}
401

The API key is missing, unknown or expired. code tells the three causes apart: missing_api_key (no Authorization: Bearer header), invalid_api_key (unknown or revoked key, or invalid format) and expired_api_key (expiration date has passed).

missing_api_key
{
  "error": {
    "type": "authentication_error",
    "code": "missing_api_key",
    "message": "No API key was provided.",
    "hint": "Add an Authorization header in the form: Bearer cap_live_<your_key>",
    "doc_url": "https://capturia.io/en/developers/api/v1/authentication#missing_api_key",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7"
  }
}
invalid_api_key
{
  "error": {
    "type": "authentication_error",
    "code": "invalid_api_key",
    "message": "API key is invalid or has been revoked.",
    "hint": "Verify the key in your dashboard or generate a new one.",
    "doc_url": "https://capturia.io/en/developers/api/v1/authentication#invalid_api_key",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7"
  }
}
expired_api_key
{
  "error": {
    "type": "authentication_error",
    "code": "expired_api_key",
    "message": "API key has expired.",
    "hint": "Roll the key from the dashboard to generate a new valid one.",
    "doc_url": "https://capturia.io/en/developers/api/v1/authentication#expired_api_key",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7"
  }
}
403

Authorization refused. code tells apart the refusals the operation returns under this status, and each example shows one.

browser_not_allowed
{
  "error": {
    "type": "authorization_error",
    "code": "browser_not_allowed",
    "message": "API keys must be used from a server, never from a browser.",
    "hint": "The request carries an `Origin` header: call the API from your server, where the key stays secret.",
    "doc_url": "https://capturia.io/en/developers/api/v1/errors#browser_not_allowed",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7"
  }
}
account_suspended
{
  "error": {
    "type": "authorization_error",
    "code": "account_suspended",
    "message": "Access to this account is suspended by the Capturia team.",
    "hint": "The refusal comes from the account, not the key. While the suspension lasts, no request is accepted: contact the Capturia team.",
    "doc_url": "https://capturia.io/en/developers/api/v1/authentication#account_suspended",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7"
  }
}
feature_not_available
{
  "error": {
    "type": "authorization_error",
    "code": "feature_not_available",
    "message": "This feature is not included in your plan.",
    "hint": "The rejection comes from the account's plan, not the key. Contact your Capturia advisor to talk it over.",
    "doc_url": "https://capturia.io/en/developers/api/v1/authentication#plan",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7",
    "details": {
      "feature": "public_api"
    }
  }
}
insufficient_scope
{
  "error": {
    "type": "authorization_error",
    "code": "insufficient_scope",
    "message": "This API key does not contain the required scope for this endpoint.",
    "hint": "This key is missing the `conversations:import` scope. Create a new key with the \"Read + write\" preset or add the scope via the dashboard.",
    "doc_url": "https://capturia.io/en/developers/api/v1/authentication#scopes",
    "dashboard_url": "https://capturia.io/platform/dashboard/admin/integrations/api-keys/6f1e2d3c-4b5a-4c6d-8e7f-9a0b1c2d3e4f?tab=permissions",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7",
    "details": {
      "required_scope": "conversations:import",
      "required_permission": "call_review.manage",
      "current_scopes": [
        "leads:capture"
      ],
      "suggested_preset": "read_write"
    }
  }
}
404

contact_not_found: contact.id points to no contact on this account. Nothing is recorded: send the ID of a contact on the account, or remove contact.id so Capturia looks up the contact by its other identifiers.

contact_not_found
{
  "error": {
    "type": "not_found_error",
    "code": "contact_not_found",
    "message": "No contact on this account has this ID (`contact.id`). Nothing was saved.",
    "hint": "Check `contact.id`, or remove it so Capturia looks up the contact by `external_id`, phone or email: an unknown person gets a contact; with `create_if_missing: false`, or without a phone number or email, the conversation waits to be attached.",
    "doc_url": "https://capturia.io/en/developers/api/v1/errors#contact_not_found",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7"
  }
}
409

Idempotency key conflict. The same Idempotency-Key was used for another body (details.reason: payload_mismatch), or the first request under this key is still in progress (in_flight, retry after Retry-After).

idempotency_conflictpayload_mismatch
{
  "error": {
    "type": "idempotency_error",
    "code": "idempotency_conflict",
    "message": "Idempotency key conflict.",
    "hint": "Either the same Idempotency-Key was used with a different payload, or a request with this key is still in progress. Use a fresh Idempotency-Key per logical request.",
    "doc_url": "https://capturia.io/en/developers/api/v1/conventions#idempotency",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7",
    "details": {
      "reason": "payload_mismatch"
    }
  }
}
idempotency_conflictin_flight
{
  "error": {
    "type": "idempotency_error",
    "code": "idempotency_conflict",
    "message": "Idempotency key conflict.",
    "hint": "Either the same Idempotency-Key was used with a different payload, or a request with this key is still in progress. Use a fresh Idempotency-Key per logical request.",
    "doc_url": "https://capturia.io/en/developers/api/v1/conventions#idempotency",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7",
    "details": {
      "reason": "in_flight"
    }
  }
}
413

The request body exceeds 1 MB (1,048,576 bytes). details.max_bytes gives the limit, and details.received_bytes the size announced by Content-Length when the request declares it.

payload_too_large
{
  "error": {
    "type": "validation_error",
    "code": "payload_too_large",
    "message": "Request body exceeds the 1 MB limit.",
    "hint": "Split your request into smaller batches.",
    "doc_url": "https://capturia.io/en/developers/api/v1/conventions#body-size",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7",
    "details": {
      "max_bytes": 1048576,
      "received_bytes": 1572864
    }
  }
}
415

The Content-Type header is missing, or isn't application/json.

invalid_content_type
{
  "error": {
    "type": "validation_error",
    "code": "invalid_content_type",
    "message": "Unsupported Content-Type.",
    "hint": "Send Content-Type: application/json on POST/PUT/PATCH requests.",
    "doc_url": "https://capturia.io/en/developers/api/v1/conventions#content-type",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7"
  }
}
422

Request refused. code tells apart the refusals the operation returns under this status, and each example shows one.

validation_errorbody · held_by_or_seller_required
{
  "error": {
    "type": "validation_error",
    "code": "validation_error",
    "message": "Request validation failed.",
    "hint": "`details` names each field to fix and the reason it was refused.",
    "doc_url": "https://capturia.io/en/developers/api/v1/errors#validation_error",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7",
    "details": [
      {
        "field": "body",
        "reason": "held_by_or_seller_required"
      }
    ]
  }
}
validation_errorcontact · invalid
{
  "error": {
    "type": "validation_error",
    "code": "validation_error",
    "message": "Request validation failed.",
    "hint": "`details` names each field to fix and the reason it was refused.",
    "doc_url": "https://capturia.io/en/developers/api/v1/errors#validation_error",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7",
    "details": [
      {
        "field": "contact",
        "reason": "invalid"
      }
    ]
  }
}
recording_notice_required
{
  "error": {
    "type": "business_rule_error",
    "code": "recording_notice_required",
    "message": "The submission doesn't confirm the person was told about the recording. Nothing was saved.",
    "hint": "Send `recording_notice: \"given\"` only when every person in the conversation was told it is recorded and analyzed by artificial intelligence.",
    "doc_url": "https://capturia.io/en/developers/api/v1/errors#recording_notice_required",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7"
  }
}
import_attestation_missing
{
  "error": {
    "type": "business_rule_error",
    "code": "import_attestation_missing",
    "message": "The account's management hasn't signed the attestation for conversations sent by a provider. Nothing was saved.",
    "hint": "Have an owner or admin of the account sign it in Administration › Imported conversations, then resend the conversation.",
    "doc_url": "https://capturia.io/en/developers/api/v1/errors#import_attestation_missing",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7"
  }
}
contact_refused_recording
{
  "error": {
    "type": "business_rule_error",
    "code": "contact_refused_recording",
    "message": "The person on this contact refused to be recorded: their contact receives no conversation. Nothing was saved.",
    "hint": "Don't resend this conversation. If the person changes their mind, an account member removes the refusal on their contact.",
    "doc_url": "https://capturia.io/en/developers/api/v1/errors#contact_refused_recording",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7"
  }
}
transcript_unreadable
{
  "error": {
    "type": "validation_error",
    "code": "transcript_unreadable",
    "message": "The transcript contains no readable speaking turn, or its times aren't those of a conversation.",
    "hint": "Send the text as is in `transcript.text` (one \"Name: text\" line per turn, or a WebVTT or SRT file), or the turns in `transcript.turns`. Times count from the start of the conversation, over one day at most, the end never before the start.",
    "doc_url": "https://capturia.io/en/developers/api/v1/errors#transcript_unreadable",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7"
  }
}
transcript_too_short
{
  "error": {
    "type": "validation_error",
    "code": "transcript_too_short",
    "message": "The transcript is too short to be analyzed.",
    "hint": "`details.min_words` gives the minimum number of words. A shorter conversation has nothing to analyze.",
    "doc_url": "https://capturia.io/en/developers/api/v1/errors#transcript_too_short",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7",
    "details": {
      "min_words": 15
    }
  }
}
transcript_too_long
{
  "error": {
    "type": "validation_error",
    "code": "transcript_too_long",
    "message": "The transcript is over the allowed size.",
    "hint": "`details.max_characters` gives the limit. A longer conversation is sent by its audio recording (`media`).",
    "doc_url": "https://capturia.io/en/developers/api/v1/errors#transcript_too_long",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7",
    "details": {
      "max_characters": 500000
    }
  }
}
unsupported_media_type
{
  "error": {
    "type": "validation_error",
    "code": "unsupported_media_type",
    "message": "This audio format isn't accepted.",
    "hint": "`details.allowed` lists the accepted types. Convert the recording, or send its transcript.",
    "doc_url": "https://capturia.io/en/developers/api/v1/errors#unsupported_media_type",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7",
    "details": {
      "allowed": [
        "audio/mpeg",
        "audio/mp4",
        "audio/m4a",
        "audio/x-m4a",
        "audio/wav",
        "audio/x-wav",
        "audio/aac",
        "audio/ogg",
        "audio/opus",
        "audio/webm",
        "audio/flac",
        "audio/amr",
        "audio/3gpp"
      ]
    }
  }
}
media_too_large
{
  "error": {
    "type": "validation_error",
    "code": "media_too_large",
    "message": "The audio file is over the allowed size.",
    "hint": "`details.max_bytes` gives the limit. Send the conversation's transcript instead.",
    "doc_url": "https://capturia.io/en/developers/api/v1/errors#media_too_large",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7",
    "details": {
      "max_bytes": 268435456
    }
  }
}
seller_not_found
{
  "error": {
    "type": "business_rule_error",
    "code": "seller_not_found",
    "message": "The named seller isn't an active member of the account. Nothing was saved.",
    "hint": "Check `seller.email` or `seller.id`, or remove `seller`: the conversation then goes to the record's seller, otherwise to the account's default seller.",
    "doc_url": "https://capturia.io/en/developers/api/v1/errors#seller_not_found",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7"
  }
}
meeting_type_not_found
{
  "error": {
    "type": "business_rule_error",
    "code": "meeting_type_not_found",
    "message": "The named meeting type doesn't exist or was removed. Nothing was saved.",
    "hint": "Check `meeting_type_id`, or remove it: the conversation then takes the account's default type.",
    "doc_url": "https://capturia.io/en/developers/api/v1/errors#meeting_type_not_found",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7"
  }
}
upload_incomplete
{
  "error": {
    "type": "business_rule_error",
    "code": "upload_incomplete",
    "message": "The audio file didn't arrive complete. The submission was removed.",
    "hint": "Resend the conversation to get a new upload link, then upload the whole file before calling `complete`.",
    "doc_url": "https://capturia.io/en/developers/api/v1/errors#upload_incomplete",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7"
  }
}
429

Limit reached. rate_limit_exceeded: the key's hourly quota is used up. too_many_attempts: too many invalid keys presented from this IP address. rate_limited_ip: more than 120 requests per minute from this IP address on this endpoint, whatever the key; the X-RateLimit-Scope header is then ip. For these three codes, Retry-After gives the delay in seconds. import_daily_limit_reached: the account has received today (UTC) the number of conversations it can receive per day; nothing is recorded, send the conversation again the next day. This refusal counts toward the key's quota.

rate_limit_exceeded
{
  "error": {
    "type": "rate_limit_error",
    "code": "rate_limit_exceeded",
    "message": "Rate limit exceeded.",
    "hint": "Retry after the number of seconds in retry_after_seconds, and consider implementing exponential backoff.",
    "doc_url": "https://capturia.io/en/developers/api/v1/rate-limits",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7",
    "details": {
      "limit": 100,
      "count": 100,
      "limit_type": "per_key",
      "retry_after_seconds": 42
    }
  }
}
too_many_attempts
{
  "error": {
    "type": "rate_limit_error",
    "code": "too_many_attempts",
    "message": "Too many invalid authentication attempts from this IP.",
    "hint": "Wait the period indicated by retry_after_seconds before trying again.",
    "doc_url": "https://capturia.io/en/developers/api/v1/authentication#brute-force",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7",
    "details": {
      "limit_type": "brute_force",
      "retry_after_seconds": 300
    }
  }
}
rate_limited_ip
{
  "error": {
    "type": "rate_limit_error",
    "code": "rate_limited_ip",
    "message": "IP rate limit reached.",
    "hint": "`details` gives the limit and the window in seconds. Wait for the `Retry-After` header's delay before retrying.",
    "doc_url": "https://capturia.io/en/developers/api/v1/errors#rate_limited_ip",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7",
    "details": {
      "limit": 120,
      "window_seconds": 60
    }
  }
}
import_daily_limit_reached
{
  "error": {
    "type": "business_rule_error",
    "code": "import_daily_limit_reached",
    "message": "This account has reached today's limit of imported conversations. Nothing was saved.",
    "hint": "The limit counts per day (UTC) and per account. Resend the conversation tomorrow.",
    "doc_url": "https://capturia.io/en/developers/api/v1/errors#import_daily_limit_reached",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7"
  }
}
500

Unexpected server error. Always include the request_id when contacting support.

internal_error
{
  "error": {
    "type": "server_error",
    "code": "internal_error",
    "message": "Server error. The Capturia team has been notified.",
    "hint": "If this persists, contact support and include the request_id from this response.",
    "doc_url": "https://capturia.io/en/developers/api/v1/errors#internal_error",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7"
  }
}
501

Test keys (cap_test_) aren't served yet: only cap_live_ keys are accepted.

not_implemented
{
  "error": {
    "type": "server_error",
    "code": "not_implemented",
    "message": "This feature is not yet implemented.",
    "hint": "Check the API documentation for available features and the changelog for upcoming releases.",
    "doc_url": "https://capturia.io/en/developers/api/v1/errors#not_implemented",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7"
  }
}
503

A service the request depends on didn't respond (reading the key, the account or the plan). The same request will go through once it's back: retry after the Retry-After delay.

service_unavailable
{
  "error": {
    "type": "server_error",
    "code": "service_unavailable",
    "message": "Service temporarily unavailable.",
    "hint": "Retry after the period indicated by Retry-After.",
    "doc_url": "https://capturia.io/en/developers/api/v1/errors#service_unavailable",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7"
  }
}

Example request

curl -X POST 'https://api.capturia.io/v1/conversation-imports' \
  -H 'Authorization: Bearer cap_live_<your-key>' \
  -H 'Content-Type: application/json' \
  -d '{
  "transcript": {
    "text": "Julie : Bonjour, ici Julie d'Appels Pro. Je vous appelle au sujet de votre demande de soumission pour la cuisine.\nMarc : Oui, bonjour. On aimerait refaire les armoires et le comptoir avant le printemps.\nJulie : Parfait. Quel budget avez-vous en tête pour le projet ?\nMarc : Autour de vingt mille dollars, installation comprise.\n"
  },
  "speakers": {
    "Julie": "agent",
    "Marc": "prospect"
  },
  "recording_notice": "given",
  "held_by": {
    "name": "Julie Bouchard",
    "organization": "Appels Pro"
  },
  "contact": {
    "phone": "+15145551234",
    "first_name": "Marc"
  },
  "occurred_at": "2026-11-04T14:30:00-05:00",
  "channel": "phone",
  "external_id": "appel-88213",
  "external_source": "appels-pro",
  "source_label": "Appels Pro"
}'
post/v1/conversation-imports/complete

Complete an audio upload

Tell Capturia that the audio file announced through POST /v1/conversation-imports is uploaded at the upload link. Capturia checks that it arrived whole, at the announced size, then has it transcribed and analyzed (status: processing). Replayable: an upload already completed returns the same response.

The body names the submission by its ID (id), the one returned by POST /v1/conversation-imports.

Required scopes: conversations:import

Request body

PropertyTypeRequiredDescription
idstringrequiredThe ID of the submission whose audio file is uploaded, as returned by POST /v1/conversation-imports.

Responses

StatusDescription
200

File received. The conversation goes to its transcription, then to its analysis.

400

Invalid request. code tells apart the refusals the operation returns under this status, and each example shows one.

invalid_request
{
  "error": {
    "type": "validation_error",
    "code": "invalid_request",
    "message": "Request format is invalid.",
    "hint": "Check that headers, body and JSON encoding match the API contract documented in the API Reference.",
    "doc_url": "https://capturia.io/en/developers/api/v1/errors#invalid_request",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7"
  }
}
invalid_encoding
{
  "error": {
    "type": "validation_error",
    "code": "invalid_encoding",
    "message": "Request encoding must be UTF-8.",
    "hint": "Use Content-Type: application/json; charset=utf-8.",
    "doc_url": "https://capturia.io/en/developers/api/v1/conventions#encoding",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7"
  }
}
invalid_json
{
  "error": {
    "type": "validation_error",
    "code": "invalid_json",
    "message": "The request body is not valid JSON.",
    "hint": "Check the JSON syntax (quotes, commas, braces) and its UTF-8 encoding.",
    "doc_url": "https://capturia.io/en/developers/api/v1/errors#invalid_json",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7"
  }
}
invalid_body
{
  "error": {
    "type": "validation_error",
    "code": "invalid_body",
    "message": "The request body must be a JSON object.",
    "hint": "Send an object (`{ ... }`): this endpoint accepts no array, string or number.",
    "doc_url": "https://capturia.io/en/developers/api/v1/errors#invalid_body",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7"
  }
}
validation_errorid · required
{
  "error": {
    "type": "validation_error",
    "code": "validation_error",
    "message": "Request validation failed.",
    "hint": "`details` names each field to fix and the reason it was refused.",
    "doc_url": "https://capturia.io/en/developers/api/v1/errors#validation_error",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7",
    "details": [
      {
        "field": "id",
        "reason": "required"
      }
    ]
  }
}
validation_errorid · invalid_uuid
{
  "error": {
    "type": "validation_error",
    "code": "validation_error",
    "message": "Request validation failed.",
    "hint": "`details` names each field to fix and the reason it was refused.",
    "doc_url": "https://capturia.io/en/developers/api/v1/errors#validation_error",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7",
    "details": [
      {
        "field": "id",
        "reason": "invalid_uuid"
      }
    ]
  }
}
401

The API key is missing, unknown or expired. code tells the three causes apart: missing_api_key (no Authorization: Bearer header), invalid_api_key (unknown or revoked key, or invalid format) and expired_api_key (expiration date has passed).

missing_api_key
{
  "error": {
    "type": "authentication_error",
    "code": "missing_api_key",
    "message": "No API key was provided.",
    "hint": "Add an Authorization header in the form: Bearer cap_live_<your_key>",
    "doc_url": "https://capturia.io/en/developers/api/v1/authentication#missing_api_key",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7"
  }
}
invalid_api_key
{
  "error": {
    "type": "authentication_error",
    "code": "invalid_api_key",
    "message": "API key is invalid or has been revoked.",
    "hint": "Verify the key in your dashboard or generate a new one.",
    "doc_url": "https://capturia.io/en/developers/api/v1/authentication#invalid_api_key",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7"
  }
}
expired_api_key
{
  "error": {
    "type": "authentication_error",
    "code": "expired_api_key",
    "message": "API key has expired.",
    "hint": "Roll the key from the dashboard to generate a new valid one.",
    "doc_url": "https://capturia.io/en/developers/api/v1/authentication#expired_api_key",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7"
  }
}
403

Authorization refused. code tells apart the refusals the operation returns under this status, and each example shows one.

browser_not_allowed
{
  "error": {
    "type": "authorization_error",
    "code": "browser_not_allowed",
    "message": "API keys must be used from a server, never from a browser.",
    "hint": "The request carries an `Origin` header: call the API from your server, where the key stays secret.",
    "doc_url": "https://capturia.io/en/developers/api/v1/errors#browser_not_allowed",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7"
  }
}
account_suspended
{
  "error": {
    "type": "authorization_error",
    "code": "account_suspended",
    "message": "Access to this account is suspended by the Capturia team.",
    "hint": "The refusal comes from the account, not the key. While the suspension lasts, no request is accepted: contact the Capturia team.",
    "doc_url": "https://capturia.io/en/developers/api/v1/authentication#account_suspended",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7"
  }
}
feature_not_available
{
  "error": {
    "type": "authorization_error",
    "code": "feature_not_available",
    "message": "This feature is not included in your plan.",
    "hint": "The rejection comes from the account's plan, not the key. Contact your Capturia advisor to talk it over.",
    "doc_url": "https://capturia.io/en/developers/api/v1/authentication#plan",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7",
    "details": {
      "feature": "public_api"
    }
  }
}
insufficient_scope
{
  "error": {
    "type": "authorization_error",
    "code": "insufficient_scope",
    "message": "This API key does not contain the required scope for this endpoint.",
    "hint": "This key is missing the `conversations:import` scope. Create a new key with the \"Read + write\" preset or add the scope via the dashboard.",
    "doc_url": "https://capturia.io/en/developers/api/v1/authentication#scopes",
    "dashboard_url": "https://capturia.io/platform/dashboard/admin/integrations/api-keys/6f1e2d3c-4b5a-4c6d-8e7f-9a0b1c2d3e4f?tab=permissions",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7",
    "details": {
      "required_scope": "conversations:import",
      "required_permission": "call_review.manage",
      "current_scopes": [
        "leads:capture"
      ],
      "suggested_preset": "read_write"
    }
  }
}
404

resource_not_found: no received submission on this account has this ID (unknown, from another account, refused or removed).

resource_not_found
{
  "error": {
    "type": "not_found_error",
    "code": "resource_not_found",
    "message": "The requested resource was not found.",
    "hint": "Verify the resource ID. It may have been deleted or never existed.",
    "doc_url": "https://capturia.io/en/developers/api/v1/errors#resource_not_found",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7"
  }
}
413

The request body exceeds 1 MB (1,048,576 bytes). details.max_bytes gives the limit, and details.received_bytes the size announced by Content-Length when the request declares it.

payload_too_large
{
  "error": {
    "type": "validation_error",
    "code": "payload_too_large",
    "message": "Request body exceeds the 1 MB limit.",
    "hint": "Split your request into smaller batches.",
    "doc_url": "https://capturia.io/en/developers/api/v1/conventions#body-size",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7",
    "details": {
      "max_bytes": 1048576,
      "received_bytes": 1572864
    }
  }
}
415

The Content-Type header is missing, or isn't application/json.

invalid_content_type
{
  "error": {
    "type": "validation_error",
    "code": "invalid_content_type",
    "message": "Unsupported Content-Type.",
    "hint": "Send Content-Type: application/json on POST/PUT/PATCH requests.",
    "doc_url": "https://capturia.io/en/developers/api/v1/conventions#content-type",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7"
  }
}
422

The upload can't be completed. business_rule_violation: details.reason is not_an_audio_import (the submission is a transcript, already sent to analysis) or upload_not_received (the file isn't at the upload link yet: upload it, then call complete again). upload_incomplete: the uploaded file doesn't have the announced size; the submission is removed, send the conversation again to get a new upload link.

business_rule_violationnot_an_audio_import
{
  "error": {
    "type": "business_rule_error",
    "code": "business_rule_violation",
    "message": "A business rule prevents this operation.",
    "hint": "`details` names the rule that blocks the operation. The endpoint's reference lists each possible value and what it requires.",
    "doc_url": "https://capturia.io/en/developers/api/v1/errors#business_rule_violation",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7",
    "details": {
      "reason": "not_an_audio_import"
    }
  }
}
business_rule_violationupload_not_received
{
  "error": {
    "type": "business_rule_error",
    "code": "business_rule_violation",
    "message": "A business rule prevents this operation.",
    "hint": "`details` names the rule that blocks the operation. The endpoint's reference lists each possible value and what it requires.",
    "doc_url": "https://capturia.io/en/developers/api/v1/errors#business_rule_violation",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7",
    "details": {
      "reason": "upload_not_received"
    }
  }
}
upload_incomplete
{
  "error": {
    "type": "business_rule_error",
    "code": "upload_incomplete",
    "message": "The audio file didn't arrive complete. The submission was removed.",
    "hint": "Resend the conversation to get a new upload link, then upload the whole file before calling `complete`.",
    "doc_url": "https://capturia.io/en/developers/api/v1/errors#upload_incomplete",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7"
  }
}
429

Rate limit reached. rate_limit_exceeded: the key's hourly quota is used up. too_many_attempts: too many invalid keys presented from this IP address (brute-force protection). In both cases, Retry-After gives the delay in seconds.

rate_limit_exceeded
{
  "error": {
    "type": "rate_limit_error",
    "code": "rate_limit_exceeded",
    "message": "Rate limit exceeded.",
    "hint": "Retry after the number of seconds in retry_after_seconds, and consider implementing exponential backoff.",
    "doc_url": "https://capturia.io/en/developers/api/v1/rate-limits",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7",
    "details": {
      "limit": 100,
      "count": 100,
      "limit_type": "per_key",
      "retry_after_seconds": 42
    }
  }
}
too_many_attempts
{
  "error": {
    "type": "rate_limit_error",
    "code": "too_many_attempts",
    "message": "Too many invalid authentication attempts from this IP.",
    "hint": "Wait the period indicated by retry_after_seconds before trying again.",
    "doc_url": "https://capturia.io/en/developers/api/v1/authentication#brute-force",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7",
    "details": {
      "limit_type": "brute_force",
      "retry_after_seconds": 300
    }
  }
}
500

Unexpected server error. Always include the request_id when contacting support.

internal_error
{
  "error": {
    "type": "server_error",
    "code": "internal_error",
    "message": "Server error. The Capturia team has been notified.",
    "hint": "If this persists, contact support and include the request_id from this response.",
    "doc_url": "https://capturia.io/en/developers/api/v1/errors#internal_error",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7"
  }
}
501

Test keys (cap_test_) aren't served yet: only cap_live_ keys are accepted.

not_implemented
{
  "error": {
    "type": "server_error",
    "code": "not_implemented",
    "message": "This feature is not yet implemented.",
    "hint": "Check the API documentation for available features and the changelog for upcoming releases.",
    "doc_url": "https://capturia.io/en/developers/api/v1/errors#not_implemented",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7"
  }
}
503

A service the request depends on didn't respond: reading the key, the account or the plan, or the storage that checks the uploaded file. The same request will go through once it's back: retry after the Retry-After delay.

service_unavailable
{
  "error": {
    "type": "server_error",
    "code": "service_unavailable",
    "message": "Service temporarily unavailable.",
    "hint": "Retry after the period indicated by Retry-After.",
    "doc_url": "https://capturia.io/en/developers/api/v1/errors#service_unavailable",
    "request_id": "req_01J9X8Z3F4K2M5N7P9Q1R3S5T7"
  }
}

Example request

curl -X POST 'https://api.capturia.io/v1/conversation-imports/complete' \
  -H 'Authorization: Bearer cap_live_<your-key>' \
  -H 'Content-Type: application/json' \
  -d '{
  "id": "6a7b8c9d-0e1f-4a2b-9c3d-4e5f6a7b8c9d"
}'