> ## Documentation Index
> Fetch the complete documentation index at: https://docs.raidzero.icu/llms.txt
> Use this file to discover all available pages before exploring further.

# Rust

> sf_voice_media Rust SDK reference: async client built on reqwest and tokio with a builder pattern for ingesting assets and searching media.

`sf_voice_media` — async, built on `reqwest`. Requires `tokio`.

Use this SDK inside Tokio services or jobs where ingest and polling should be part of the same async runtime.

## Install

Add to `Cargo.toml`:

```toml theme={null}
[dependencies]
sf_voice_media = "0.1.1"
tokio = { version = "1", features = ["full"] }
```

## Create a client

```rust theme={null}
use sf_voice_media::SfVoiceMedia;

let client = SfVoiceMedia::new(
    "https://api.sf-voice.com",
    std::env::var("SF_VOICE_API_KEY").unwrap(),
)?;
```

## Ingest

```rust theme={null}
use sf_voice_media::types::{IngestRequest, MediaType};

let mut request = IngestRequest::from_url_with_asset_id(
    "call_001",
    "https://storage.example.com/calls/001.mp3",
).media_kind(MediaType::Audio);
request.asset_class = Some("customer_acme".into());
let resp = client.ingest(&request).await?;

let task_id = resp.task_id;
```

S3:

```rust theme={null}
use sf_voice_media::types::{IngestRequest, MediaType};

let mut request = IngestRequest::from_s3_with_asset_id(
    "call_001",
    "calls/customer_acme/001.mp3",
).media_kind(MediaType::Audio);
request.asset_class = Some("customer_acme".into());
let resp = client.ingest(&request).await?;
```

## Poll until ready

```rust theme={null}
use sf_voice_media::types::TaskStatus;
use std::time::Duration;

let task = client.poll_task(
    &task_id,
    Duration::from_millis(1_500),
    Duration::from_secs(120),
).await?;

match task.status {
    TaskStatus::Ready => println!("indexed: {}", task.asset_id),
    TaskStatus::Failed => eprintln!("failed: {:?}", task.error),
    _ => unreachable!(),
}
```

Pass the polling interval and total timeout as `Duration` values.

## Search

```rust theme={null}
use sf_voice_media::types::SearchRequest;

let mut request = SearchRequest::new("customer asks about pricing")
    .threshold(0.7)
    .limit(10);
request.asset_class = Some("customer_acme".into());
let resp = client.search(&request).await?;

for result in &resp.results {
    println!("{} {}–{}ms ({:.2})", result.asset_id, result.start_ms, result.end_ms, result.score);
}
```

## Assets

```rust theme={null}
// list
let resp = client.list_assets(None, None).await?;

// get one
let asset = client.get_asset("call_001").await?;

// delete
client.delete_asset("call_001").await?;
```

## Errors

```rust theme={null}
use sf_voice_media::SfVoiceMediaError;

match client.search(req).await {
    Ok(resp) => { /* use resp */ }
    Err(SfVoiceMediaError::Api { code, message, status }) => {
        eprintln!("api error {status} [{code}]: {message}");
    }
    Err(SfVoiceMediaError::Http(e)) => {
        eprintln!("transport error: {e}");
    }
    Err(SfVoiceMediaError::PollTimeout { task_id }) => {
        eprintln!("timed out polling {task_id}");
    }
}
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.