1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
extern crate reqwest;
extern crate serde_json;
use crate::error::{PaystackError, RequestNotSuccessful};
use crate::response::TransactionStatus;
use crate::{PaystackResult, TransactionResponse};
static BASE_URL: &str = "https://api.paystack.co";
/// This is the struct that allows you to authenticate to the PayStack API.
/// It contains the API key which allows you to interact with the API.
#[derive(Clone, Debug)]
pub struct PaystackClient {
client: reqwest::Client,
api_key: String,
}
/// This struct is used to create a transaction body for creating a transaction using the Paystack API.
///
/// The struct has the following fields:
/// - amount: Amount should be in the smallest unit of the currency e.g. kobo if in NGN and cents if in USD
/// - email: Customer's email address
/// - currency (Optional): The transaction currency (NGN, GHS, ZAR or USD). Defaults to your integration currency.
/// - plan (Optional): If transaction is to create a subscription to a predefined plan, provide plan code here.
/// This would invalidate the value provided in amount
/// - transaction_charge (Optional): An amount used to override the split configuration for a single split payment.
/// If set, the amount specified goes to the main account regardless of the split configuration.
/// - bearer (Optional): Who bears Paystack charges? account or subaccount (defaults to account).
#[derive(serde::Serialize)]
pub struct TransactionBody {
pub amount: String,
pub email: String,
pub currency: Option<String>,
pub plan: Option<String>,
pub transaction_charge: Option<i32>,
pub bearer: Option<String>,
}
impl PaystackClient {
/// Create a new PayStack client with the specified API key.
///
/// It takes the following parameters:
/// - key: Paystack API key.
pub fn new<S: Into<String>>(key: S) -> Self {
Self {
client: reqwest::Client::new(),
api_key: key.into(),
}
}
/// Initalize a new transaction using the Paystack API.
///
/// The function takes a TransactionBody type as its parameter
///
pub async fn initialize_transaction(
&self,
transaction_body: TransactionBody,
) -> PaystackResult<TransactionResponse> {
let url = format!("{}/transaction/initialize", BASE_URL);
let response = self
.client
.post(url)
.bearer_auth(&self.api_key)
.header("Content-Type", "application/json")
.json(&transaction_body)
.send()
.await?;
if let Err(_ex) = response.error_for_status_ref() {
return Err(
RequestNotSuccessful::new(response.status(), response.text().await?).into(),
);
}
let contents = response.json::<TransactionResponse>().await?;
Ok(contents)
}
/// This function confirms the status of a transaction.
///
/// It takes the following parameters:
/// - reference: The transaction reference used to intiate the transaction
pub async fn verify_transaction(&self, reference: String) -> PaystackResult<TransactionStatus> {
let url = format!("{}/transaction/verify/{}", BASE_URL, reference);
let response = self
.client
.get(url)
.bearer_auth(&self.api_key)
.header("Content-Type", "application/json")
.send()
.await?;
if let Err(ex) = response.error_for_status_ref() {
return Err(PaystackError::Generic(ex.to_string()));
}
let contents = response.json::<TransactionStatus>().await?;
Ok(contents)
}
}