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

# Rust

> reqwest para convertir documentos desde Rust.

# Rust

## Dependencias

```toml theme={null}
# Cargo.toml
[dependencies]
reqwest = { version = "0.12", features = ["json"] }
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
```

## Archivo local

```rust theme={null}
use reqwest::Client;
use std::fs;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = Client::new();
    let pdf = fs::read("informe.pdf")?;

    let res = client
        .post("https://api.markpdf.tech/convert/raw")
        .query(&[("filename", "informe.pdf"), ("mode", "fast")])
        .header("x-api-key", "TU_API_KEY")
        .header("content-type", "application/pdf")
        .body(pdf)
        .send()
        .await?;

    let markdown = res.text().await?;
    println!("{markdown}");
    Ok(())
}
```

## URL firmada

```rust theme={null}
use reqwest::Client;
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = Client::new();

    let res = client
        .post("https://api.markpdf.tech/convert/from-url")
        .header("x-api-key", "TU_API_KEY")
        .json(&json!({
            "url": "https://bucket.s3.amazonaws.com/informe.pdf?X-Amz-Signature=...",
            "filename": "informe.pdf",
            "mode": "fast"
        }))
        .send()
        .await?;

    println!("{}", res.text().await?);
    Ok(())
}
```

## Manejo de 202 (auto-async)

Cuando todos los backends están saturados, la API devuelve `202`. Pollea `/jobs/{id}` hasta obtener el resultado:

```rust theme={null}
use reqwest::Client;
use serde::Deserialize;
use std::fs;
use tokio::time::{sleep, Duration};

const API_URL: &str = "https://api.markpdf.tech";
const API_KEY: &str = "TU_API_KEY";

#[derive(Deserialize)]
struct AcceptedJob {
    job_id: String,
    retry_after_seconds: Option<u64>,
}

#[derive(Deserialize)]
struct JobStatus {
    status: String,
    body: Option<String>,
    error: Option<String>,
}

async fn convert(client: &Client, pdf: Vec<u8>, filename: &str) -> Result<String, Box<dyn std::error::Error>> {
    let res = client
        .post(format!("{API_URL}/convert/raw"))
        .query(&[("filename", filename), ("mode", "fast")])
        .header("x-api-key", API_KEY)
        .header("content-type", "application/pdf")
        .body(pdf)
        .send()
        .await?;

    match res.status().as_u16() {
        200 => Ok(res.text().await?),
        202 => {
            let job: AcceptedJob = res.json().await?;
            let delay = Duration::from_secs(job.retry_after_seconds.unwrap_or(5));

            loop {
                sleep(delay).await;
                let poll = client
                    .get(format!("{API_URL}/jobs/{}", job.job_id))
                    .header("x-api-key", API_KEY)
                    .send()
                    .await?
                    .json::<JobStatus>()
                    .await?;

                match poll.status.as_str() {
                    "completed" => return Ok(poll.body.unwrap_or_default()),
                    "failed" => return Err(poll.error.unwrap_or("unknown".into()).into()),
                    _ => continue,
                }
            }
        }
        code => Err(format!("HTTP {code}: {}", res.text().await?).into()),
    }
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = Client::new();
    let pdf = fs::read("informe.pdf")?;
    let markdown = convert(&client, pdf, "informe.pdf").await?;
    println!("{markdown}");
    Ok(())
}
```
