reevit 0.2.0

Official Rust SDK for the Reevit payments API
Documentation

Reevit Rust SDK

The official async Rust client for the Reevit payments API.

Installation

[dependencies]
reevit = "0.1"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }

Quick start

Amounts use the smallest currency unit. For example, 5000 means GHS 50.00.

use reevit::{Client, PaymentIntentRequest, RequestOptions};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = Client::builder("pfk_test_xxx.secret", "org_123").build()?;

    let payment = client
        .payments()
        .create_intent(
            &PaymentIntentRequest {
                amount: 5_000,
                currency: "GHS".into(),
                method: Some("mobile_money".into()),
                country: "GH".into(),
                reference: Some("ORD-12345".into()),
                ..PaymentIntentRequest::default()
            },
            RequestOptions::default().idempotency_key("ORD-12345"),
        )
        .await?;

    println!("created payment {}", payment.id);
    Ok(())
}

The client sends X-Reevit-Key and X-Org-Id on every request, defaults to https://api.reevit.io, and uses a 30-second timeout. Override the URL or timeout through Client::builder for tests and specialized deployments.

Server-created checkout sessions

Create a session on your server and pass only its session_secret to a Reevit React, Vue, or Svelte checkout SDK.

# use reevit::{Client, PaymentIntentRequest, RequestOptions};
# async fn example(client: &Client) -> reevit::Result<()> {
let session = client
    .checkout_sessions()
    .create(
        &PaymentIntentRequest {
            amount: 5_000,
            currency: "GHS".into(),
            country: "GH".into(),
            ..PaymentIntentRequest::default()
        },
        RequestOptions::default().idempotency_key("ORD-12345"),
    )
    .await?;

println!("session secret: {}", session.session_secret);
# Ok(())
# }

Webhook verification

Verify the exact bytes received from Reevit. Parsing and re-serializing JSON can change whitespace or key order and invalidate a correct signature.

use reevit::verify_webhook_signature;

let raw_body = br#"{"id":"evt_123","type":"payment.succeeded"}"#;
let signature = "sha256=2f70e6b9d3f5f7dd-placeholder";

if verify_webhook_signature(raw_body, signature, "whsec_xxx") {
    // Process the verified event.
}

Resource modules

  • client.payments()
  • client.checkout_sessions()
  • client.connections()
  • client.subscriptions()
  • client.fraud()
  • client.customers()
  • client.payment_links()
  • client.webhooks()
  • client.routing_rules()
  • client.invoices()

All mutating methods accept RequestOptions. Reuse the same idempotency key when retrying the same logical mutation. The SDK does not automatically retry payment mutations.

Connection listing is explicit about pagination: connections().list(...) returns one page, connections().list_page(...) retains the server's pagination metadata, and connections().list_all(...) fetches every matching PSP connection.

Errors

reevit::Error::Api preserves the HTTP status, Reevit error code, details, and request ID. is_recoverable() identifies transport failures and HTTP statuses that may succeed when retried; callers still decide whether retrying a specific operation is safe.

Development

cargo fmt --all -- --check
cargo clippy --all-targets --all-features -- -D warnings
cargo test --all-features
cargo test --doc
cargo publish --dry-run --locked

License

MIT