Official Python SDK for the Conduit API
Project description
Conduit Python SDK
This repository publishes the official Python SDK for Conduit and mirrors the package source from the main Conduit monorepo. The SDK is maintained as part of the main project; this repository exists to provide a focused public package home for Python consumers.
Conduit is a behavioral intelligence API with two stable workflows:
reportsturns a recording into a structured behavioral report for a selected speaker.matchingcompares one target against a group in a closed interpretation context.
The Python package name is mappa-conduit. The import surface is conduit.
Install
pip install mappa-conduit
Python version
mappa-conduit requires Python 3.12 or newer.
API surface
The stable public surface is:
conduit.reports.create(...)conduit.reports.get(...)conduit.matching.create(...)conduit.matching.get(...)conduit.webhooks.verify_signature(...)conduit.webhooks.parse_event(...)conduit.primitives.entities.*conduit.primitives.media.*conduit.primitives.jobs.*
Use reports first. matching is also stable. primitives is the advanced,
lower-level surface for upload, reuse, inspection, and backoffice flows.
Choose a workflow
- Use
reports.create(...)when you want to analyze one speaker from a recording. - Use
matching.create(...)when you want to compare one target against a group. - Use webhooks as the primary completion path in production.
- Use
receipt.handle.wait()for local scripts and development. - Use
receipt.handle.stream()when you want live job stage updates. - Use
conduit.primitives.media.upload(...)when you want to upload once and reuse amedia_idlater.
Quickstart
Report creation is receipt-first and asynchronous. reports.create(...) never
waits for report completion. It resolves the source, uploads if needed, creates
the job, and returns a receipt immediately.
from conduit import Conduit
conduit = Conduit(api_key="sk_...")
receipt = conduit.reports.create(
source={"url": "https://storage.example.com/call.wav"},
output={"template": "general_report"},
target={"strategy": "dominant"},
webhook={"url": "https://my-app.com/webhooks/conduit"},
idempotency_key="signup-call-42",
)
print(receipt.job_id)
print(receipt.status)
What the receipt contains
job_id: accepted job identifierstatus: usuallyqueuedorrunningstage: current stage when availableestimated_wait_sec: advisory wait estimate when availablemedia_id: included for report creation when the SDK knows ithandle: convenience helpers for waiting, streaming, fetching job state, and cancellation
Verified webhook handling
Webhooks are the primary production completion path. Always verify the raw body
before parsing the event. Delivery is at-least-once, so consumers should dedupe
on event.id.
from pathlib import Path
from conduit import Conduit
conduit = Conduit(api_key="sk_...")
def has_seen(event_id: str) -> bool:
return Path(f"/tmp/{event_id}").exists()
def mark_seen(event_id: str) -> None:
Path(f"/tmp/{event_id}").touch()
def handle_webhook(raw_payload: bytes, headers: dict[str, str]) -> None:
conduit.webhooks.verify_signature(
raw_payload,
headers,
secret="whsec_...",
)
event = conduit.webhooks.parse_event(raw_payload)
if has_seen(event.id):
return
if event.type == "report.completed":
report_id = event.data["reportId"]
report = conduit.reports.get(report_id)
print(report.output.markdown)
if event.type == "report.failed":
print(event.data["error"]["message"])
if event.type == "matching.completed":
matching_id = event.data["matchingId"]
matching = conduit.matching.get(matching_id)
print(matching.output.markdown)
if event.type == "matching.failed":
print(event.data["error"]["message"])
mark_seen(event.id)
Webhook behavior
- Verify before parsing.
verify_signature(...)expects the exact raw request body.- Header lookup is case-insensitive and uses
conduit-signature. - Known event types are validated for shape.
- Unknown future event types are returned without rejection so consumers can forward-handle them safely.
Common report workflows
Create a report from a local file path
receipt = conduit.reports.create(
source={"path": "recordings/demo-call.wav"},
output={"template": "general_report"},
target={"strategy": "dominant"},
)
Upload media once, then reuse media_id
media = conduit.primitives.media.upload(path="recordings/demo-call.wav")
receipt = conduit.reports.create(
source={"media_id": media.media_id},
output={"template": "sales_playbook"},
target={"strategy": "entity_id", "entity_id": "ent_123"},
)
Wait locally for the completed report
handle.wait() is a convenience for scripts and local development. It is not
the recommended production path.
report = receipt.handle.wait(timeout_ms=300_000)
print(report.output.template)
print(report.output.markdown)
Stream job events
for event in receipt.handle.stream(timeout_ms=300_000):
print(event.type, event.job.status, event.stage, event.progress)
Fetch current job state or request cancellation
job = receipt.handle.job()
print(job.status)
job = receipt.handle.cancel()
print(job.status)
Fetch a report only if it already exists
maybe_report = receipt.handle.report()
if maybe_report is not None:
print(maybe_report.id)
Matching
Matching is also receipt-first and asynchronous.
matching_receipt = conduit.matching.create(
context="hiring_team_fit",
target={"entity_id": "ent_candidate"},
group=[
{"entity_id": "ent_manager"},
{
"media_id": "med_panel",
"selector": {"strategy": "dominant"},
},
],
webhook={"url": "https://my-app.com/webhooks/conduit"},
)
print(matching_receipt.job_id)
Matching constraints
contextis currently a closed enum and must behiring_team_fit.targetmust be exactly one matching subject.groupmust contain at least one matching subject.- A matching subject must be either
{"entity_id": ...}or{"media_id": ..., "selector": ...}. - Duplicate direct
entity_idreferences across target and group are rejected.
Wait for a matching result
matching = matching_receipt.handle.wait(timeout_ms=300_000)
print(matching.output.markdown)
Primitives
conduit.primitives is the stable advanced surface.
Entities
entity = conduit.primitives.entities.get("ent_123")
page = conduit.primitives.entities.list(limit=20)
updated = conduit.primitives.entities.update("ent_123", {"label": "Top performer"})
Media
media = conduit.primitives.media.upload(path="recordings/demo-call.wav")
media = conduit.primitives.media.get(media.media_id)
page = conduit.primitives.media.list(limit=20)
result = conduit.primitives.media.set_retention_lock(media.media_id, locked=True)
deleted = conduit.primitives.media.delete(media.media_id)
Jobs
job = conduit.primitives.jobs.get(receipt.job_id)
job = conduit.primitives.jobs.cancel(receipt.job_id)
Request shapes
Public request dictionaries use snake_case keys.
Report source
Exactly one source variant is allowed.
{"media_id": "med_123"}
{"file": binary_file_or_bytes, "label": "call-a"}
{"url": "https://storage.example.com/call.wav", "label": "call-a"}
{"path": "recordings/call.wav", "label": "call-a"}
Rules:
- Mixed source variants are rejected before any network call.
media_id,url, andpathmust be non-empty strings.source.urlmust usehttporhttps.source.pathmust point to a file, not a directory.
Report output
{"template": "general_report"}
{"template": "sales_playbook"}
{"template": "general_report", "template_params": {...}}
Supported stable templates:
general_reportsales_playbook
Target selector
{"strategy": "dominant"}
{"strategy": "dominant", "on_miss": "fallback_dominant"}
{
"strategy": "timerange",
"time_range": {"start_seconds": 15, "end_seconds": 45},
}
{"strategy": "entity_id", "entity_id": "ent_123"}
{"strategy": "magic_hint", "hint": "the interviewer"}
Rules:
strategymust be one ofdominant,timerange,entity_id, ormagic_hint.on_missmay beerrororfallback_dominant.timerangerequires at least one bound.- If both
start_secondsandend_secondsare present,start_seconds < end_seconds.
Matching subject
{"entity_id": "ent_123"}
{
"media_id": "med_123",
"selector": {"strategy": "dominant"},
}
Webhook config
{
"url": "https://my-app.com/webhooks/conduit",
"headers": {"x-tenant-id": "tenant_123"},
}
Models you will use most often
ReportJobReceiptandMatchingJobReceiptfrom create callsReportRunHandleandMatchingRunHandleforwait(),stream(),cancel(),job(), and resource fetch helpersJobfor lifecycle stateReportandMatchingfor completed resourcesWebhookEventfor verified event envelopes
Error handling
All SDK failures use typed exceptions.
API and auth errors
ApiError: base HTTP API errorAuthError: authentication or authorization failureValidationError: invalid API payloadRateLimitError: rate-limited request; includesretry_after_mswhen availableInsufficientCreditsError: insufficient credits; includesrequiredandavailable
Source and upload errors
InvalidSourceError: invalid source shape or unsupported local sourceRemoteFetchError: remote URL fetch failureRemoteFetchTimeoutError: remote URL fetch timeoutRemoteFetchTooLargeError: remote URL exceeded the configured size limit
Job and streaming errors
JobFailedError: terminal failed jobJobCanceledError: terminal canceled jobTimeoutError: SDK deadline expiredRequestAbortedError: caller-provided cancellation signal firedStreamError: event stream failed after retries were exhausted
Example:
from conduit import (
Conduit,
JobFailedError,
RemoteFetchError,
ValidationError,
)
conduit = Conduit(api_key="sk_...")
try:
receipt = conduit.reports.create(
source={"url": "https://storage.example.com/call.wav"},
output={"template": "general_report"},
target={"strategy": "dominant"},
)
report = receipt.handle.wait(timeout_ms=300_000)
except ValidationError as error:
print(error.code)
except RemoteFetchError as error:
print(error.url, error.status)
except JobFailedError as error:
print(error.job_id)
Timeouts, retries, idempotency
Client defaults:
timeout_ms=30000max_retries=2
Behavior:
- create operations support caller-supplied
idempotency_key - transient
429and5xxAPI errors are retried automatically - transport timeouts and transport failures are wrapped in typed SDK errors
handle.stream()reconnects automatically and resumes withLast-Event-IDwhen possiblehandle.wait()is built on top of stream semantics and raises typed terminal errors
Cancellation
Sync helpers accept a signal object with an is_set() method. A
threading.Event works well.
from threading import Event
cancel_event = Event()
report = receipt.handle.wait(signal=cancel_event)
Runtime and upload notes
| Runtime | source.file |
source.url |
source.path |
handle.wait() |
handle.stream() |
webhooks.verify_signature() |
|---|---|---|---|---|---|---|
| CPython server runtime | Yes | Yes | Yes | Yes | Yes | Yes |
Important notes:
source.urlcauses the SDK host to fetch the remote origin before upload.source.urlfollows redirects up to 5 hops.source.urlfails with typed source errors when the remote request times out, returns an error status, or exceeds the configured size budget.source.pathresolves relative paths from the current working directory.- local file uploads stream from disk where possible
- remote URL sources are buffered to a temporary file before upload
- webhook verification requires the exact raw request body, not parsed JSON
Client configuration
from conduit import Conduit
conduit = Conduit(
api_key="sk_...",
base_url="https://api.mappa.ai",
timeout_ms=30_000,
max_retries=2,
)
Supported configuration:
api_key: required API keybase_url: API base URLtimeout_ms: per-request timeout budget in millisecondsmax_retries: retry budget for transient failuresmax_source_bytes: source upload limit guarduser_agent: optional custom user agenthttp_client: optional customhttpx.Clienttelemetry: optional request/response/error hooks
If you pass a custom http_client, the SDK uses it for requests instead of
creating its own client.
Typing
The package ships with type information, including typed request dictionaries, models, receipts, handles, and error classes.
Preferred public keys are snake_case:
media_identity_idtemplate_paramstime_rangestart_secondsend_secondson_miss
Local checks
bun run check
bun run type-check
bun run test
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mappa_conduit-0.1.9.tar.gz.
File metadata
- Download URL: mappa_conduit-0.1.9.tar.gz
- Upload date:
- Size: 25.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d2fc2f27f025ece431317c4a8b205e93f93fab8301d986067bc90535e03631d4
|
|
| MD5 |
c08957fcf273517542e60780b582296b
|
|
| BLAKE2b-256 |
7963af51234d6bfb04acdc5af42be85ce90f6a7e023415eb364a12b046465703
|
Provenance
The following attestation bundles were made for mappa_conduit-0.1.9.tar.gz:
Publisher:
publish.yml on mappa-ai/conduit-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mappa_conduit-0.1.9.tar.gz -
Subject digest:
d2fc2f27f025ece431317c4a8b205e93f93fab8301d986067bc90535e03631d4 - Sigstore transparency entry: 1109090178
- Sigstore integration time:
-
Permalink:
mappa-ai/conduit-python@c39ad0de9c8207f892bed33e239e35e48954e80f -
Branch / Tag:
refs/tags/v0.1.9 - Owner: https://github.com/mappa-ai
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c39ad0de9c8207f892bed33e239e35e48954e80f -
Trigger Event:
push
-
Statement type:
File details
Details for the file mappa_conduit-0.1.9-py3-none-any.whl.
File metadata
- Download URL: mappa_conduit-0.1.9-py3-none-any.whl
- Upload date:
- Size: 30.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1cd4867e5b4497a5157264638c8e2ffe83cddfd514716b6f1f89a866c61a52b8
|
|
| MD5 |
04738d719747004cbadfd33f1edb8bc0
|
|
| BLAKE2b-256 |
c14e54e5320277728e53119f78bba6a633e931c0dbccd9276cc81b725e95878a
|
Provenance
The following attestation bundles were made for mappa_conduit-0.1.9-py3-none-any.whl:
Publisher:
publish.yml on mappa-ai/conduit-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mappa_conduit-0.1.9-py3-none-any.whl -
Subject digest:
1cd4867e5b4497a5157264638c8e2ffe83cddfd514716b6f1f89a866c61a52b8 - Sigstore transparency entry: 1109090184
- Sigstore integration time:
-
Permalink:
mappa-ai/conduit-python@c39ad0de9c8207f892bed33e239e35e48954e80f -
Branch / Tag:
refs/tags/v0.1.9 - Owner: https://github.com/mappa-ai
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c39ad0de9c8207f892bed33e239e35e48954e80f -
Trigger Event:
push
-
Statement type: