= iran-pay
image:https://img.shields.io/crates/v/iran-pay.svg[crates.io,link=https://crates.io/crates/iran-pay] image:https://docs.rs/iran-pay/badge.svg[docs.rs,link=https://docs.rs/iran-pay] image:https://github.com/obsernetics/rust-lib/actions/workflows/ci.yml/badge.svg[CI,link=https://github.com/obsernetics/rust-lib/actions/workflows/ci.yml] image:https://img.shields.io/badge/license-Apache--2.0-blue.svg[License] image:https://img.shields.io/badge/MSRV-1.88-orange.svg[MSRV] image:https://deps.rs/repo/github/obsernetics/rust-lib/status.svg[Dependencies,link=https://deps.rs/repo/github/obsernetics/rust-lib]
Unified async SDK for Iranian payment gateways.
== Features
- ZarinPal driver — production v4 JSON API + sandbox.
- IDPay driver —
X-API-KEYJSON API + sandbox header. - NextPay driver — form-encoded API with
code: -1semantics. - Pay.ir driver — form-encoded API with the magic
"test"sandbox key. - Single dyn-safe
Gatewaytrait — swap providers with one line at runtime. Amounttype with explicit Toman / Rial unit constructors — eliminates the most common Iranian-payment-integration bug at the type level.- Built-in
MockGatewayfor fast, deterministic, network-free unit tests of your checkout code. - Re-export of the
parsitextIranian validators (national ID, IBAN, bank-card, mobile, postal code, car plate) — pre-flight buyer input before you call the gateway. tracinginstrumentation on every driver method (provider name, amount, authority surfaced as fields).- Strongly-typed
thiserrorerror enum: transport, gateway-business, amount mismatch, configuration, decode, and unsupported-operation variants are all separate. - Async-first (
async-trait), Tokio-friendly, no blocking calls.
=== Optional features
[cols="1,1,3", options="header"] |=== | Feature | Default | What it enables
| zarinpal | ✓ | Compile the providers::ZarinPal driver
| idpay | ✓ | Compile the providers::IDPay driver
| nextpay | ✓ | Compile the providers::NextPay driver
| payir | ✓ | Compile the providers::PayIr driver
| validators | ✓ | Re-export parsitext's Iranian validators
| rustls-tls | ✓ | Use rustls for HTTPS (no system OpenSSL needed)
| native-tls | | Use the platform TLS library instead of rustls
|===
Disabling all four provider features still builds the trait, types, and mock gateway — useful when you bring your own driver against this abstraction.
== Quick start
[source,toml]
[dependencies] iran-pay = "0.1.1" tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
Or pick only the providers you need:
iran-pay = { version = "0.1.1", default-features = false, features = ["zarinpal", "rustls-tls"] }
[source,rust]
use iran_pay::providers::ZarinPal; use iran_pay::{Amount, Gateway, StartRequest, VerifyRequest};
#[tokio::main] async fn main() -> Result<(), iran_pay::Error> { let gateway = ZarinPal::new("YOUR-MERCHANT-UUID").sandbox();
// 1. Initiate the payment.
let start = gateway.start_payment(&StartRequest::builder()
.amount(Amount::toman(50_000))
.description("Pro subscription — May 2026")
.callback_url("https://example.com/payment/callback")
.order_id("ORD-12345")
.build()).await?;
// 2. Redirect the user to `start.payment_url`.
println!("Send user to: {}", start.payment_url);
// 3. After they return, verify. Pass the same amount back in to
// catch tampering with the callback query string.
let verified = gateway.verify_payment(&VerifyRequest {
authority: start.authority,
amount: Amount::toman(50_000),
}).await?;
println!("Paid! Transaction ID = {}", verified.transaction_id);
Ok(())
}
== Examples
Each runnable example lives in examples/:
[cols="1,2", options="header"] |=== | Example | What it demonstrates
| zarinpal_basic | Minimal start-payment flow against the ZarinPal sandbox.
| multi_gateway | Box<dyn Gateway> polymorphism — register all four providers and look them up by key.
| with_validators | Use the validators re-export to check bank cards / mobiles / operators before calling the gateway.
| mock_in_test | Drop MockGateway into your own service tests; assert call counts and script failures.
|===
Run with:
[source,bash]
cargo run --example -p iran-pay
== Comparison
[cols="1,1,1,1", options="header"]
|===
| Capability | iran-pay | JS iranianbank / iranian-bank-gateways | Hand-rolled reqwest
| Unified Gateway trait | ✓ | partial (per-provider classes) | ✗
| Typed Amount (Toman / Rial) | ✓ (compile-time) | ✗ (raw numbers) | ✗
| Async / Tokio-native | ✓ | ✓ (Node) | yes (manual)
| tracing instrumentation | ✓ (built-in spans) | ✗ | manual
| Mock driver shipped with the SDK | ✓ | ✗ | ✗
| Strong error taxonomy | ✓ (thiserror) | strings / Error | ad-hoc
| Iranian validators bundled | ✓ (via parsitext) | separate package | ✗
|===
== Documentation
[source,bash]
cargo doc -p iran-pay --all-features
Hosted docs: link:https://docs.rs/iran-pay[docs.rs/iran-pay].
== License
Apache-2.0.