1use anyhow::{Result, anyhow};
2use serde::Deserialize;
3
4const BIRDEYE_CREDITS_URL: &str = "https://public-api.birdeye.so/utils/v1/credits";
5
6#[derive(Deserialize, Debug)]
7pub struct BirdeyeCreditsResponse {
8 data: Option<BirdeyeCreditsData>,
9 remaining: Option<BirdeyeRemaining>, }
11
12#[derive(Deserialize, Debug)]
13pub struct BirdeyeCreditsData {
14 remaining: BirdeyeRemaining,
15 usage: BirdeyeUsage,
16}
17
18#[derive(Deserialize, Debug)]
19pub struct BirdeyeRemaining {
20 total: f64,
21}
22
23#[derive(Deserialize, Debug)]
24pub struct BirdeyeUsage {
25 total: f64,
26}
27
28#[derive(Clone)]
29pub struct BirdeyeClient {
30 api_key: String,
31 client: reqwest::Client,
32}
33
34impl BirdeyeClient {
35 pub fn new(api_key: &str) -> Self {
36 Self {
37 api_key: api_key.to_string(),
38 client: reqwest::Client::new(),
39 }
40 }
41
42 pub async fn get_credits(&self) -> Result<(f64, f64)> {
43 let res = self
44 .client
45 .get(BIRDEYE_CREDITS_URL)
46 .header("X-API-KEY", &self.api_key)
47 .header("accept", "application/json")
48 .send()
49 .await?;
50
51 if !res.status().is_success() {
52 let status = res.status();
53 let text = res.text().await?;
54 return Err(anyhow!(
55 "Birdeye credits request failed: {} - {}",
56 status,
57 text
58 ));
59 }
60
61 let json: BirdeyeCreditsResponse = res.json().await?;
62
63 let (remaining, total) = if let Some(data) = json.data {
64 let remaining = data.remaining.total;
65 let usage_total = data.usage.total;
66 (remaining, remaining + usage_total)
67 } else if let Some(remaining_data) = json.remaining {
68 let remaining = remaining_data.total;
70 (remaining, remaining) } else {
72 (0.0, 0.0)
73 };
74
75 Ok((remaining, total))
76 }
77}