use crate::client::Client;
use crate::error::Result;
use crate::models::*;
use serde_json::{json, Value};
fn take_idempotency_key(params: Value) -> (Value, Option<String>) {
match params {
Value::Object(mut m) => {
let key = m
.remove("idempotency_key")
.and_then(|v| v.as_str().map(|s| s.trim().to_string()))
.filter(|s| !s.is_empty());
(Value::Object(m), key)
}
other => (other, None),
}
}
fn batch_body(field: &str, items: Vec<Value>, on_error: Option<&str>) -> Value {
let mut body = json!({ field: items });
if let Some(mode) = on_error {
body["on_error"] = json!(mode);
}
body
}
fn page(limit: Option<i64>, offset: Option<i64>) -> Value {
let mut m = serde_json::Map::new();
if let Some(l) = limit {
m.insert("limit".into(), json!(l));
}
if let Some(o) = offset {
m.insert("offset".into(), json!(o));
}
Value::Object(m)
}
fn lookup(uuid: Option<&str>, order_id: Option<&str>) -> Value {
let mut m = serde_json::Map::new();
if let Some(u) = uuid {
m.insert("uuid".into(), json!(u));
}
if let Some(o) = order_id {
m.insert("order_id".into(), json!(o));
}
Value::Object(m)
}
pub struct Payments<'a> {
pub(crate) client: &'a Client,
}
impl Payments<'_> {
pub fn create(&self, params: Value) -> Result<Payment> {
let (body, key) = take_idempotency_key(params);
self.client.request_idempotent("/v1/payment", &body, key)
}
pub fn info(&self, uuid: Option<&str>, order_id: Option<&str>) -> Result<Payment> {
self.client
.request("/v1/payment/info", &lookup(uuid, order_id))
}
pub fn history(&self, params: Value) -> Result<PaymentList> {
self.client.request("/v1/payment/history", ¶ms)
}
pub fn services(&self) -> Result<Vec<ServiceMethod>> {
self.client.request("/v1/payment/services", &json!({}))
}
pub fn qr(&self, uuid: Option<&str>, order_id: Option<&str>) -> Result<Value> {
self.client
.request("/v1/payment/qr", &lookup(uuid, order_id))
}
pub fn resend(&self, uuid: Option<&str>, order_id: Option<&str>) -> Result<Value> {
self.client
.request("/v1/payment/resend", &lookup(uuid, order_id))
}
pub fn refund(&self, params: Value) -> Result<Value> {
let (body, key) = take_idempotency_key(params);
self.client
.request_idempotent("/v1/payment/refund", &body, key)
}
pub fn list_accepted(&self) -> Result<Value> {
self.client.request("/v1/payment/accepted/list", &json!({}))
}
pub fn set_accepted(&self, accepted: Vec<AcceptedMethod>) -> Result<Value> {
self.client
.request("/v1/payment/accepted/set", &json!({ "accepted": accepted }))
}
pub fn get_accuracy(&self) -> Result<Value> {
self.client.request("/v1/payment/accuracy/get", &json!({}))
}
pub fn set_accuracy(&self, params: Value) -> Result<Value> {
self.client.request("/v1/payment/accuracy/set", ¶ms)
}
pub fn get_autorefund(&self) -> Result<Value> {
self.client
.request("/v1/payment/autorefund/get", &json!({}))
}
pub fn set_autorefund(&self, params: Value) -> Result<Value> {
self.client.request("/v1/payment/autorefund/set", ¶ms)
}
pub fn set_discount(&self, params: Value) -> Result<Value> {
self.client.request("/v1/payment/discount/set", ¶ms)
}
pub fn list_discounts(&self) -> Result<Value> {
self.client.request("/v1/payment/discount/list", &json!({}))
}
pub fn create_batch(
&self,
payments: Vec<Value>,
on_error: Option<&str>,
) -> Result<BatchSubmission> {
self.client.request_idempotent(
"/v1/payment/batch",
&batch_body("payments", payments, on_error),
None,
)
}
pub fn refund_batch(
&self,
refunds: Vec<Value>,
on_error: Option<&str>,
) -> Result<BatchSubmission> {
self.client.request_idempotent(
"/v1/refund/batch",
&batch_body("refunds", refunds, on_error),
None,
)
}
pub fn send_email(
&self,
uuid: Option<&str>,
order_id: Option<&str>,
email: Option<&str>,
) -> Result<Value> {
let mut body = lookup(uuid, order_id);
if let Some(e) = email {
body["email"] = json!(e);
}
self.client.request("/v1/payment/send-email", &body)
}
pub fn resolve(&self, action: ResolveAction, params: Value) -> Result<Resolution> {
let (mut body, key) = take_idempotency_key(params);
if let Value::Object(m) = &mut body {
m.insert("action".into(), json!(action.as_str()));
}
self.client
.request_idempotent("/v1/payment/resolve", &body, key)
}
}
pub struct Payouts<'a> {
pub(crate) client: &'a Client,
}
impl Payouts<'_> {
pub fn create(&self, params: Value) -> Result<Payout> {
let (body, key) = take_idempotency_key(params);
self.client.request_idempotent("/v1/payout", &body, key)
}
pub fn create_mass(
&self,
payouts: Vec<Value>,
source: Option<&str>,
) -> Result<MassPayoutResult> {
let mut body = json!({ "payouts": payouts });
if let Some(s) = source {
body["source"] = json!(s);
}
self.client
.request_idempotent("/v1/payout/mass", &body, None)
}
pub fn create_batch(
&self,
payouts: Vec<Value>,
on_error: Option<&str>,
) -> Result<BatchSubmission> {
self.client.request_idempotent(
"/v1/payout/batch",
&batch_body("payouts", payouts, on_error),
None,
)
}
pub fn info(&self, uuid: Option<&str>, order_id: Option<&str>) -> Result<Payout> {
self.client
.request("/v1/payout/info", &lookup(uuid, order_id))
}
pub fn history(&self, params: Value) -> Result<PayoutList> {
self.client.request("/v1/payout/history", ¶ms)
}
pub fn services(&self) -> Result<Vec<ServiceMethod>> {
self.client.request("/v1/payout/services", &json!({}))
}
pub fn calculate(&self, params: Value) -> Result<PayoutCalculation> {
self.client.request("/v1/payout/calculate", ¶ms)
}
pub fn approve(&self, uuid: &str) -> Result<Value> {
self.client
.request("/v1/payout/approve", &json!({ "uuid": uuid }))
}
pub fn refund(&self, params: Value) -> Result<Value> {
let (body, key) = take_idempotency_key(params);
self.client
.request_idempotent("/v1/payment/refund", &body, key)
}
pub fn get_fee_config(&self) -> Result<Value> {
self.client.request("/v1/payout/fee-config/get", &json!({}))
}
pub fn set_fee_config(&self, fee_on_recipient: bool) -> Result<Value> {
self.client.request(
"/v1/payout/fee-config/set",
&json!({ "fee_on_recipient": fee_on_recipient }),
)
}
pub fn get_refund_fee_config(&self) -> Result<Value> {
self.client
.request("/v1/payout/refund-fee-config/get", &json!({}))
}
pub fn set_refund_fee_config(&self, fee_on_customer: bool) -> Result<Value> {
self.client.request(
"/v1/payout/refund-fee-config/set",
&json!({ "fee_on_customer": fee_on_customer }),
)
}
}
pub struct Wallets<'a> {
pub(crate) client: &'a Client,
}
impl Wallets<'_> {
pub fn create(&self, params: Value) -> Result<Wallet> {
self.client.request("/v1/wallet", ¶ms)
}
pub fn block(&self, address: &str, force_block: Option<bool>) -> Result<Value> {
let mut body = json!({ "address": address });
if let Some(f) = force_block {
body["is_force_block"] = json!(f);
}
self.client.request("/v1/wallet/block", &body)
}
pub fn blocked_address_refund(&self, uuid: &str, address: &str) -> Result<Value> {
self.client.request(
"/v1/wallet/blocked-address-refund",
&json!({ "uuid": uuid, "address": address }),
)
}
pub fn qr(&self, address: &str) -> Result<Value> {
self.client
.request("/v1/wallet/qr", &json!({ "address": address }))
}
}
pub struct Account<'a> {
pub(crate) client: &'a Client,
}
impl Account<'_> {
pub fn balance(&self) -> Result<Balance> {
#[derive(serde::Deserialize)]
struct Wrapper {
balance: Balance,
}
let w: Wrapper = self.client.request("/v1/balance", &json!({}))?;
Ok(w.balance)
}
pub fn referral(&self) -> Result<ReferralInfo> {
self.client.request("/v1/referral/info", &json!({}))
}
pub fn transfer_to_personal(&self, params: Value) -> Result<Value> {
let (body, key) = take_idempotency_key(params);
self.client
.request_idempotent("/v1/transfer/to-personal", &body, key)
}
pub fn vrcs(&self, enabled: Option<bool>) -> Result<Value> {
let body = match enabled {
Some(e) => json!({ "enabled": e }),
None => json!({}),
};
self.client.request("/v1/vrcs", &body)
}
}
pub struct Webhooks<'a> {
pub(crate) client: &'a Client,
}
impl Webhooks<'_> {
pub fn register(&self, url: &str) -> Result<WebhookRegistration> {
self.client.request("/v1/webhooks", &json!({ "url": url }))
}
pub fn deliveries(&self) -> Result<Vec<Delivery>> {
#[derive(serde::Deserialize)]
struct Wrapper {
#[serde(default)]
deliveries: Vec<Delivery>,
}
let w: Wrapper = self.client.request("/v1/webhooks/deliveries", &json!({}))?;
Ok(w.deliveries)
}
pub fn test_payment(&self, params: Value) -> Result<Value> {
self.client.request("/v1/test-webhook/payment", ¶ms)
}
pub fn test_wallet(&self, params: Value) -> Result<Value> {
self.client.request("/v1/test-webhook/wallet", ¶ms)
}
pub fn test_payout(&self, params: Value) -> Result<Value> {
self.client.request("/v1/test-webhook/payout", ¶ms)
}
}
pub struct Settings<'a> {
pub(crate) client: &'a Client,
}
impl Settings<'_> {
pub fn list_auto_withdraw(&self) -> Result<Vec<AutoWithdrawRule>> {
#[derive(serde::Deserialize)]
struct Wrapper {
#[serde(default)]
rules: Vec<AutoWithdrawRule>,
}
let w: Wrapper = self.client.request("/v1/auto-withdraw/list", &json!({}))?;
Ok(w.rules)
}
pub fn set_auto_withdraw(&self, params: Value) -> Result<Value> {
self.client.request("/v1/auto-withdraw/set", ¶ms)
}
pub fn delete_auto_withdraw(&self, currency: &str) -> Result<Value> {
self.client
.request("/v1/auto-withdraw/delete", &json!({ "currency": currency }))
}
pub fn list_allowlist(&self) -> Result<Value> {
self.client.request("/v1/api-allowlist/list", &json!({}))
}
pub fn add_allowlist(&self, cidr: &str) -> Result<Value> {
self.client
.request("/v1/api-allowlist/add", &json!({ "cidr": cidr }))
}
pub fn remove_allowlist(&self, cidr: &str) -> Result<Value> {
self.client
.request("/v1/api-allowlist/remove", &json!({ "cidr": cidr }))
}
pub fn enable_allowlist(&self, enabled: bool) -> Result<Value> {
self.client
.request("/v1/api-allowlist/enable", &json!({ "enabled": enabled }))
}
}
pub struct Rates<'a> {
pub(crate) client: &'a Client,
}
impl Rates<'_> {
pub fn list(&self, currency_from: Option<&str>) -> Result<Vec<ExchangeRate>> {
let body = match currency_from {
Some(c) => json!({ "currency_from": c }),
None => json!({}),
};
self.client.request_public("/v1/exchange-rate/list", &body)
}
pub fn currencies(&self) -> Result<Vec<Currency>> {
#[derive(serde::Deserialize)]
struct Wrap {
#[serde(default)]
currencies: Vec<Currency>,
}
let w: Wrap = self.client.request_public_get("/v1/currencies")?;
Ok(w.currencies)
}
}
pub struct Batches<'a> {
pub(crate) client: &'a Client,
}
impl Batches<'_> {
pub fn info(
&self,
batch_id: &str,
limit: Option<i64>,
offset: Option<i64>,
) -> Result<BatchInfo> {
let mut body = page(limit, offset);
body["batch_id"] = json!(batch_id);
self.client.request("/v1/batch/info", &body)
}
}
pub struct PaymentLinks<'a> {
pub(crate) client: &'a Client,
}
impl PaymentLinks<'_> {
pub fn create(&self, params: Value) -> Result<PaymentLink> {
self.client.request("/v1/payment/link", ¶ms)
}
pub fn list(&self, limit: Option<i64>, offset: Option<i64>) -> Result<Vec<PaymentLink>> {
#[derive(serde::Deserialize)]
struct Wrap {
#[serde(default)]
items: Vec<PaymentLink>,
}
let w: Wrap = self
.client
.request("/v1/payment/link/list", &page(limit, offset))?;
Ok(w.items)
}
pub fn info(&self, link_id: &str) -> Result<PaymentLink> {
self.client
.request("/v1/payment/link/info", &json!({ "link_id": link_id }))
}
pub fn toggle(&self, link_id: &str, active: bool) -> Result<PaymentLink> {
self.client.request(
"/v1/payment/link/toggle",
&json!({ "link_id": link_id, "active": active }),
)
}
pub fn public_get(&self, link_id: &str) -> Result<Value> {
self.client
.request_public_get(&format!("/v1/link/{link_id}"))
}
pub fn checkout(&self, link_id: &str, params: Value) -> Result<Payment> {
self.client
.request_public(&format!("/v1/link/{link_id}/checkout"), ¶ms)
}
}
pub struct Splits<'a> {
pub(crate) client: &'a Client,
}
impl Splits<'_> {
pub fn create_rule(&self, params: Value) -> Result<SplitRule> {
self.client.request("/v1/split/rule", ¶ms)
}
pub fn split_to_address(
&self,
address: &str,
network: &str,
percent: f64,
note: Option<&str>,
) -> Result<SplitRule> {
let mut params = serde_json::json!({
"address": address, "network": network, "percent": percent,
});
if let Some(n) = note {
params["note"] = Value::String(n.to_owned());
}
self.create_rule(params)
}
pub fn split_to_merchant(
&self,
merchant_id: &str,
percent: f64,
note: Option<&str>,
) -> Result<SplitRule> {
let mut params = serde_json::json!({
"merchant_id": merchant_id, "percent": percent,
});
if let Some(n) = note {
params["note"] = Value::String(n.to_owned());
}
self.create_rule(params)
}
pub fn list_rules(&self) -> Result<Vec<SplitRule>> {
#[derive(serde::Deserialize)]
struct Wrap {
#[serde(default)]
items: Vec<SplitRule>,
}
let w: Wrap = self.client.request("/v1/split/rule/list", &json!({}))?;
Ok(w.items)
}
pub fn delete_rule(&self, rule_id: &str) -> Result<Value> {
self.client
.request("/v1/split/rule/delete", &json!({ "rule_id": rule_id }))
}
pub fn get_config(&self) -> Result<SplitConfig> {
self.client.request("/v1/split/config/get", &json!({}))
}
pub fn set_config(&self, refund_hold_hours: i64) -> Result<Value> {
self.client.request(
"/v1/split/config/set",
&json!({ "refund_hold_hours": refund_hold_hours }),
)
}
}
pub struct PayoutLinks<'a> {
pub(crate) client: &'a Client,
}
impl PayoutLinks<'_> {
pub fn create(&self, params: Value) -> Result<PayoutLink> {
self.client.request("/v1/payout/link", ¶ms)
}
pub fn create_batch(&self, links: Vec<Value>) -> Result<PayoutLinkBatch> {
self.client
.request("/v1/payout/link/batch", &json!({ "links": links }))
}
pub fn list(&self, limit: Option<i64>, offset: Option<i64>) -> Result<Vec<PayoutLink>> {
#[derive(serde::Deserialize)]
struct Wrap {
#[serde(default)]
links: Vec<PayoutLink>,
}
let w: Wrap = self
.client
.request("/v1/payout/link/list", &page(limit, offset))?;
Ok(w.links)
}
pub fn info(&self, link_id: &str) -> Result<PayoutLink> {
self.client
.request("/v1/payout/link/info", &json!({ "link_id": link_id }))
}
pub fn cancel(&self, link_id: &str) -> Result<PayoutLink> {
self.client
.request("/v1/payout/link/cancel", &json!({ "link_id": link_id }))
}
pub fn claim_info(&self, token: &str) -> Result<ClaimInfo> {
self.client
.request_public_get(&format!("/v1/claim/{token}"))
}
pub fn claim(&self, token: &str, address: &str, memo: Option<&str>) -> Result<ClaimResult> {
let mut body = json!({ "address": address });
if let Some(m) = memo {
body["memo"] = json!(m);
}
self.client
.request_public(&format!("/v1/claim/{token}"), &body)
}
}