openai-oxide 0.17.0

Idiomatic Rust client for the OpenAI API — 1:1 parity with the official Python SDK
Documentation
// Content provenance checks — client.content_provenance_checks().create()

use crate::client::OpenAI;
#[cfg(not(target_arch = "wasm32"))]
use crate::error::OpenAIError;
#[cfg(not(target_arch = "wasm32"))]
use crate::types::content_provenance::{ContentProvenanceCheck, ContentProvenanceCheckParams};

/// Check whether an image or audio file carries known OpenAI provenance
/// signals: a C2PA content-credentials manifest or a SynthID watermark.
///
/// `not_detected` does not prove human origin — metadata may be stripped, the
/// watermark degraded, or the file generated by another company's model.
///
/// OpenAI guide: <https://platform.openai.com/docs/guides/content-provenance>
pub struct ContentProvenanceChecks<'a> {
    client: &'a OpenAI,
}

impl<'a> ContentProvenanceChecks<'a> {
    pub(crate) fn new(client: &'a OpenAI) -> Self {
        Self { client }
    }

    /// Check a file (bytes + filename) for OpenAI provenance signals.
    ///
    /// `POST /content_provenance_checks`
    #[cfg(not(target_arch = "wasm32"))]
    pub async fn create(
        &self,
        params: ContentProvenanceCheckParams,
    ) -> Result<ContentProvenanceCheck, OpenAIError> {
        let form = reqwest::multipart::Form::new().part(
            "file",
            reqwest::multipart::Part::bytes(params.file).file_name(params.filename),
        );
        self.client
            .post_multipart("/content_provenance_checks", form)
            .await
    }

    /// Check a file on disk for OpenAI provenance signals.
    #[cfg(not(target_arch = "wasm32"))]
    pub async fn from_path(
        &self,
        path: impl AsRef<std::path::Path>,
    ) -> Result<ContentProvenanceCheck, OpenAIError> {
        let path = path.as_ref();
        let filename = path
            .file_name()
            .and_then(|n| n.to_str())
            .unwrap_or("upload")
            .to_string();
        let data = tokio::fs::read(path).await.map_err(|e| {
            OpenAIError::InvalidArgument(format!("failed to read {}: {e}", path.display()))
        })?;
        self.create(ContentProvenanceCheckParams::new(data, filename))
            .await
    }
}

#[cfg(all(test, not(target_arch = "wasm32")))]
mod tests {
    use crate::OpenAI;
    use crate::config::ClientConfig;
    use crate::types::content_provenance::{ContentProvenanceCheckParams, ContentProvenanceResult};

    #[tokio::test]
    async fn test_content_provenance_check_create() {
        let mut server = mockito::Server::new_async().await;
        let mock = server
            .mock("POST", "/content_provenance_checks")
            .match_header("authorization", "Bearer sk-test")
            .with_status(200)
            .with_header("content-type", "application/json")
            .with_body(
                r#"{
                    "created_at": 1700000000,
                    "object": "content_provenance_check",
                    "results": [
                        {
                            "type": "c2pa",
                            "outcome": "detected",
                            "validation_state": "trusted",
                            "issuer": "OpenAI",
                            "model": "gpt-image-1",
                            "generated_at": "2026-08-19T00:00:00Z"
                        },
                        {
                            "type": "synthid",
                            "outcome": "not_detected"
                        }
                    ]
                }"#,
            )
            .create_async()
            .await;

        let client = OpenAI::with_config(ClientConfig::new("sk-test").base_url(server.url()));
        let params = ContentProvenanceCheckParams::new(vec![0xFF, 0xD8, 0xFF], "photo.jpg");

        let check = client
            .content_provenance_checks()
            .create(params)
            .await
            .unwrap();
        assert_eq!(check.object, "content_provenance_check");
        assert_eq!(check.results.len(), 2);
        match &check.results[0] {
            ContentProvenanceResult::C2pa(c2pa) => {
                assert_eq!(c2pa.issuer.as_deref(), Some("OpenAI"));
            }
            other => panic!("expected C2PA result, got {other:?}"),
        }
        assert!(matches!(
            &check.results[1],
            ContentProvenanceResult::SynthId(_)
        ));
        mock.assert_async().await;
    }
}