Skip to the content
Menu: Duos

Duos

Two-person avatars.

GET/v1/duos

List the organisation's duos

listDuosduos:readread: 600/min per keySince 2026-10-01

Newest first. While duos are closed to the organisation (GET /duos/access builderOpen: false) this answers 404.

Query parameters

  • limitinteger

    Page size, 1-200 (default 50).

  • cursorstring

    The nextCursor of the previous page.

Returns

200 A page of duos. A page: data is a list of Duo, and nextCursor fetches the next page.

Fields of data
  • idstringrequired

    Duo id (duo_…).

    pattern `^duo_.*`

  • personaIdstringrequired

    The persona sessions and portals use (its name is "A & B").

    pattern `^pa_.*`

  • source"library" | "generated" | "composed" | "upload"required

    Where its picture came from.

  • libraryKeystring | nullrequired

    The ready-made duo it was copied from.

  • peopleobject[]required
    • namestringrequired
    • gender"female" | "male"required
    • rolestring | nullrequired

      Their part in the conversation, in a few words.

    • voiceIdstring | nullrequired
  • relationshipstring | nullrequired
  • status"draft" | "ready_for_render" | "registering" | "testing" | "live" | "needs_changes" | "failed"required

    draft, then ready_for_render once published; registering and testing on the render side; live when its test run passed, or needs_changes / failed.

  • statusWordsstringrequired

    Where it is, in one plain sentence.

  • previewUrlstring | nullrequired

    Its picture (your API key reads it: it is the organisation's own avatar).

  • languagesstring[]required

    The languages a duo speaks (the ten codes GET /languages marks duo).

  • testReasonsstring[]required

    Why its test run didn't pass, in plain words (needs_changes, failed).

  • updatedAtstring (date-time)required

    ISO 8601 UTC timestamp.

  • aiGeneratedtruerequired

    Always true: the duo's video and voices are AI-generated, and so is their picture unless it is a photo you uploaded (EU AI Act Article 50(2)).

Errors

invalid_requestunauthorizedforbiddenupgrade_requirednot_foundrate_limitedserver_error

Request

curl "https://app.zentiqai.com/v1/duos?limit=20" \
  -H "Authorization: Bearer $ZENTIQ_API_KEY"
Example answer
Response
{
  "data": [
    {
      "id": "duo_cmfq2b7x10000abcd1234",
      "personaId": "pa_cmfq2b7x10000abcd1234",
      "source": "library",
      "libraryKey": "…",
      "people": [
        {
          "name": "Zoe",
          "gender": "female",
          "role": "…",
          "voiceId": "vo_cmfq2b7x10000abcd1234"
        }
      ],
      "relationship": "…"
    }
  ],
  "error": null,
  "requestId": "req_4f1c2e9a7b3d5e6f7a8b9c0d",
  "nextCursor": null
}
POST/v1/duos

Add a ready-made duo

createDuoduos:writeheavy: 20/min per keyIdempotency-KeySince 2026-10-01

A copy of a ready-made duo, as a draft: its persona ("A & B"), its picture and a voice each. It takes one of the plan's custom-avatar places (403 upgrade_required when there is none) and needs duos on the plan. Publish it to have it tested and go live. While duos are closed to the organisation (GET /duos/access builderOpen: false) this answers 404.

Body

  • source"library"required

    A copy of one of Zentiq's ready-made duos (your own duos come in a later release).

  • libraryKeystringrequired

    From GET /duos/library.

Returns

201 The new duo (draft). data is Duo.

Fields of data
  • idstringrequired

    Duo id (duo_…).

    pattern `^duo_.*`

  • personaIdstringrequired

    The persona sessions and portals use (its name is "A & B").

    pattern `^pa_.*`

  • source"library" | "generated" | "composed" | "upload"required

    Where its picture came from.

  • libraryKeystring | nullrequired

    The ready-made duo it was copied from.

  • peopleobject[]required
    • namestringrequired
    • gender"female" | "male"required
    • rolestring | nullrequired

      Their part in the conversation, in a few words.

    • voiceIdstring | nullrequired
  • relationshipstring | nullrequired
  • status"draft" | "ready_for_render" | "registering" | "testing" | "live" | "needs_changes" | "failed"required

    draft, then ready_for_render once published; registering and testing on the render side; live when its test run passed, or needs_changes / failed.

  • statusWordsstringrequired

    Where it is, in one plain sentence.

  • previewUrlstring | nullrequired

    Its picture (your API key reads it: it is the organisation's own avatar).

  • languagesstring[]required

    The languages a duo speaks (the ten codes GET /languages marks duo).

  • testReasonsstring[]required

    Why its test run didn't pass, in plain words (needs_changes, failed).

  • updatedAtstring (date-time)required

    ISO 8601 UTC timestamp.

  • aiGeneratedtruerequired

    Always true: the duo's video and voices are AI-generated, and so is their picture unless it is a photo you uploaded (EU AI Act Article 50(2)).

Errors

invalid_requestunauthorizedforbiddenupgrade_requirednot_foundconflictidempotency_conflictidempotency_in_progressrate_limitedserver_error

Request

curl -X POST "https://app.zentiqai.com/v1/duos" \
  -H "Authorization: Bearer $ZENTIQ_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "source": "library",
  "libraryKey": "…"
}'
Example answer
Response
{
  "data": {
    "id": "duo_cmfq2b7x10000abcd1234",
    "personaId": "pa_cmfq2b7x10000abcd1234",
    "source": "library",
    "libraryKey": "…",
    "people": [
      {
        "name": "Zoe",
        "gender": "female",
        "role": "…",
        "voiceId": "vo_cmfq2b7x10000abcd1234"
      }
    ],
    "relationship": "…"
  },
  "error": null,
  "requestId": "req_4f1c2e9a7b3d5e6f7a8b9c0d"
}
GET/v1/duos/{id}

Get a duo

getDuoduos:readread: 600/min per keySince 2026-10-01

Poll it after publishing: it goes live once its test run has passed. While duos are closed to the organisation (GET /duos/access builderOpen: false) this answers 404.

Path parameters

  • idstringrequired

    Duo id (duo_…); the id without its prefix is accepted too.

Returns

200 The duo. data is Duo.

Fields of data
  • idstringrequired

    Duo id (duo_…).

    pattern `^duo_.*`

  • personaIdstringrequired

    The persona sessions and portals use (its name is "A & B").

    pattern `^pa_.*`

  • source"library" | "generated" | "composed" | "upload"required

    Where its picture came from.

  • libraryKeystring | nullrequired

    The ready-made duo it was copied from.

  • peopleobject[]required
    • namestringrequired
    • gender"female" | "male"required
    • rolestring | nullrequired

      Their part in the conversation, in a few words.

    • voiceIdstring | nullrequired
  • relationshipstring | nullrequired
  • status"draft" | "ready_for_render" | "registering" | "testing" | "live" | "needs_changes" | "failed"required

    draft, then ready_for_render once published; registering and testing on the render side; live when its test run passed, or needs_changes / failed.

  • statusWordsstringrequired

    Where it is, in one plain sentence.

  • previewUrlstring | nullrequired

    Its picture (your API key reads it: it is the organisation's own avatar).

  • languagesstring[]required

    The languages a duo speaks (the ten codes GET /languages marks duo).

  • testReasonsstring[]required

    Why its test run didn't pass, in plain words (needs_changes, failed).

  • updatedAtstring (date-time)required

    ISO 8601 UTC timestamp.

  • aiGeneratedtruerequired

    Always true: the duo's video and voices are AI-generated, and so is their picture unless it is a photo you uploaded (EU AI Act Article 50(2)).

Errors

invalid_requestunauthorizedforbiddenupgrade_requirednot_foundrate_limitedserver_error

Request

curl "https://app.zentiqai.com/v1/duos/duo_123" \
  -H "Authorization: Bearer $ZENTIQ_API_KEY"
Example answer
Response
{
  "data": {
    "id": "duo_cmfq2b7x10000abcd1234",
    "personaId": "pa_cmfq2b7x10000abcd1234",
    "source": "library",
    "libraryKey": "…",
    "people": [
      {
        "name": "Zoe",
        "gender": "female",
        "role": "…",
        "voiceId": "vo_cmfq2b7x10000abcd1234"
      }
    ],
    "relationship": "…"
  },
  "error": null,
  "requestId": "req_4f1c2e9a7b3d5e6f7a8b9c0d"
}
GET/v1/duos/access

What the organisation may do with duos

getDuoAccessduos:readread: 600/min per keySince 2026-10-01

Whether duos are open to the organisation, and what its plan allows: ready-made duos, its own duos.

Returns

200 The organisation's duo access. data is DuoAccess.

Fields of data
  • builderOpenbooleanrequired

    Duos are open to the organisation (while not, every other /duos operation is 404).

  • canUsebooleanrequired

    The plan uses ready-made duos.

  • canBuildbooleanrequired

    The plan builds its own duos.

  • upgradeobject | nullrequired

    The plan that would add what's missing, and the words for it; null when nothing is.

    • planstringrequired
    • messagestringrequired

Errors

invalid_requestunauthorizedforbiddenupgrade_requiredrate_limitedserver_error

Request

curl "https://app.zentiqai.com/v1/duos/access" \
  -H "Authorization: Bearer $ZENTIQ_API_KEY"
Example answer
Response
{
  "data": {
    "builderOpen": true,
    "canUse": true,
    "canBuild": true,
    "upgrade": {
      "plan": "…",
      "message": "…"
    }
  },
  "error": null,
  "requestId": "req_4f1c2e9a7b3d5e6f7a8b9c0d"
}
GET/v1/duos/library

Zentiq's ready-made duos

listDuoLibraryduos:readread: 600/min per keySince 2026-10-01

The ready-made duos an organisation can copy (POST /duos), in library order. While duos are closed to the organisation (GET /duos/access builderOpen: false) this answers 404.

Returns

200 The library. data is a list of LibraryDuo.

Fields of data
  • keystringrequired

    What POST /duos takes as libraryKey.

  • titlestringrequired
  • scenariostring | nullrequired
  • peopleobject[]required

    The person on the left, then the one on the right.

    • namestringrequired
    • gender"female" | "male"required
    • rolestring | nullrequired

      Their part in the conversation, in a few words.

  • relationshipstring | nullrequired

    couple, colleagues, family or panel.

  • previewUrlstringrequired

    Their picture (public).

  • aiGeneratedtruerequired

    Always true: the duo's video and voices are AI-generated, and so is their picture unless it is a photo you uploaded (EU AI Act Article 50(2)).

Errors

invalid_requestunauthorizedforbiddenupgrade_requirednot_foundrate_limitedserver_error

Request

curl "https://app.zentiqai.com/v1/duos/library" \
  -H "Authorization: Bearer $ZENTIQ_API_KEY"
Example answer
Response
{
  "data": [
    {
      "key": "second_viewing",
      "title": "Mark & Susan",
      "scenario": "…",
      "people": [
        {
          "name": "Zoe",
          "gender": "female",
          "role": "…"
        }
      ],
      "relationship": "…",
      "previewUrl": "https://www.example.com"
    }
  ],
  "error": null,
  "requestId": "req_4f1c2e9a7b3d5e6f7a8b9c0d"
}
POST/v1/duos/{id}/publish

Publish a duo

publishDuoduos:writewrite: 120/min per keyIdempotency-KeySince 2026-10-01

Sends it to be set up and tested: it becomes ready_for_render, then live once its short test run (each person says a line) has passed, or needs_changes. 409 says what is still missing; a second publish while it is on its way changes nothing; a live duo is published again only after a change. Sessions and portals take it once it is live. While duos are closed to the organisation (GET /duos/access builderOpen: false) this answers 404.

Path parameters

  • idstringrequired

    Duo id (duo_…); the id without its prefix is accepted too.

Returns

200 The duo, on its way. data is Duo.

Fields of data
  • idstringrequired

    Duo id (duo_…).

    pattern `^duo_.*`

  • personaIdstringrequired

    The persona sessions and portals use (its name is "A & B").

    pattern `^pa_.*`

  • source"library" | "generated" | "composed" | "upload"required

    Where its picture came from.

  • libraryKeystring | nullrequired

    The ready-made duo it was copied from.

  • peopleobject[]required
    • namestringrequired
    • gender"female" | "male"required
    • rolestring | nullrequired

      Their part in the conversation, in a few words.

    • voiceIdstring | nullrequired
  • relationshipstring | nullrequired
  • status"draft" | "ready_for_render" | "registering" | "testing" | "live" | "needs_changes" | "failed"required

    draft, then ready_for_render once published; registering and testing on the render side; live when its test run passed, or needs_changes / failed.

  • statusWordsstringrequired

    Where it is, in one plain sentence.

  • previewUrlstring | nullrequired

    Its picture (your API key reads it: it is the organisation's own avatar).

  • languagesstring[]required

    The languages a duo speaks (the ten codes GET /languages marks duo).

  • testReasonsstring[]required

    Why its test run didn't pass, in plain words (needs_changes, failed).

  • updatedAtstring (date-time)required

    ISO 8601 UTC timestamp.

  • aiGeneratedtruerequired

    Always true: the duo's video and voices are AI-generated, and so is their picture unless it is a photo you uploaded (EU AI Act Article 50(2)).

Errors

invalid_requestunauthorizedforbiddenupgrade_requirednot_foundconflictidempotency_conflictidempotency_in_progressrate_limitedserver_error

Request

curl -X POST "https://app.zentiqai.com/v1/duos/duo_123/publish" \
  -H "Authorization: Bearer $ZENTIQ_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)"
Example answer
Response
{
  "data": {
    "id": "duo_cmfq2b7x10000abcd1234",
    "personaId": "pa_cmfq2b7x10000abcd1234",
    "source": "library",
    "libraryKey": "…",
    "people": [
      {
        "name": "Zoe",
        "gender": "female",
        "role": "…",
        "voiceId": "vo_cmfq2b7x10000abcd1234"
      }
    ],
    "relationship": "…"
  },
  "error": null,
  "requestId": "req_4f1c2e9a7b3d5e6f7a8b9c0d"
}