1use std::fmt::Display;
2
3use base64::{Engine, prelude::BASE64_STANDARD};
4use serde::{Deserialize, Serialize};
5use url::Url;
6
7use crate::types::{AmountValue, AnyJson, OutputSchema, X402Version};
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
10#[serde(rename_all = "camelCase")]
11pub struct PaymentRequirements {
12 pub scheme: String,
14 pub network: String,
16 pub max_amount_required: AmountValue,
18 pub resource: Url,
20 pub description: String,
22 pub mime_type: String,
24 pub pay_to: String,
26 pub max_timeout_seconds: u64,
28 pub asset: String,
30 #[serde(skip_serializing_if = "Option::is_none")]
32 pub output_schema: Option<OutputSchema>,
33 #[serde(skip_serializing_if = "Option::is_none")]
35 pub extra: Option<AnyJson>,
36}
37
38#[derive(Debug, Clone, Serialize, Deserialize)]
39#[serde(rename_all = "camelCase")]
40pub struct PaymentPayload {
41 pub x402_version: X402Version,
42 pub scheme: String,
43 pub network: String,
44 pub payload: AnyJson,
45}
46
47#[derive(Debug, Clone, Serialize, Deserialize)]
48#[serde(rename_all = "camelCase")]
49pub struct PaymentRequirementsResponse {
50 pub x402_version: X402Version,
51 pub error: String,
52 pub accepts: Vec<PaymentRequirements>,
53}
54
55#[derive(Debug, Clone)]
56pub struct FacilitatorPaymentRequest {
57 pub payload: FacilitatorPaymentRequestPayload,
58 pub x_payment_header: Base64EncodedHeader,
59}
60
61#[derive(Debug, Clone)]
62pub struct FacilitatorPaymentRequestPayload {
63 pub payment_payload: PaymentPayload,
64 pub payment_requirements: PaymentRequirements,
65}
66
67#[derive(Debug, Clone)]
68pub enum FacilitatorVerifyResponse {
69 Valid(FacilitatorVerifyValid),
70 Invalid(FacilitatorVerifyInvalid),
71}
72
73impl FacilitatorVerifyResponse {
74 pub fn is_valid(&self) -> bool {
75 matches!(self, FacilitatorVerifyResponse::Valid(_))
76 }
77
78 pub fn valid(valid: FacilitatorVerifyValid) -> Self {
79 FacilitatorVerifyResponse::Valid(valid)
80 }
81
82 pub fn invalid(invalid: FacilitatorVerifyInvalid) -> Self {
83 FacilitatorVerifyResponse::Invalid(invalid)
84 }
85}
86
87#[derive(Debug, Clone, Serialize, Deserialize)]
88pub struct FacilitatorVerifyValid {
89 pub payer: String,
90}
91
92#[derive(Debug, Clone, Serialize, Deserialize)]
93pub struct FacilitatorVerifyInvalid {
94 pub invalid_reason: String,
95 pub payer: Option<String>,
96}
97
98#[derive(Debug, Clone)]
99pub enum FacilitatorSettleResponse {
100 Success(FacilitatorSettleSuccess),
101 Failed(FacilitatorSettleFailed),
102}
103
104impl FacilitatorSettleResponse {
105 pub fn is_success(&self) -> bool {
106 matches!(self, FacilitatorSettleResponse::Success(_))
107 }
108
109 pub fn success(success: FacilitatorSettleSuccess) -> Self {
110 FacilitatorSettleResponse::Success(success)
111 }
112
113 pub fn failed(failed: FacilitatorSettleFailed) -> Self {
114 FacilitatorSettleResponse::Failed(failed)
115 }
116}
117
118#[derive(Debug, Clone, Serialize, Deserialize)]
119pub struct FacilitatorSettleSuccess {
120 pub payer: String,
121 pub transaction: String,
122 pub network: String,
123}
124
125#[derive(Debug, Clone, Serialize, Deserialize)]
126pub struct FacilitatorSettleFailed {
127 pub error_reason: String,
128 pub payer: Option<String>,
129}
130
131#[derive(Debug, Clone, Serialize, Deserialize)]
132#[serde(rename_all = "camelCase")]
133pub struct FacilitatorSupportedKinds {
134 pub x402_version: X402Version,
135 pub scheme: String,
136 pub network: String,
137 pub extra: Option<AnyJson>,
138}
139
140#[derive(Debug, Clone, Serialize, Deserialize)]
141#[serde(rename_all = "camelCase")]
142pub struct FacilitatorSupportedResponse {
143 pub kinds: Vec<FacilitatorSupportedKinds>,
144}
145
146#[derive(Debug, Clone, Serialize, Deserialize)]
147#[serde(rename_all = "camelCase")]
148pub struct PaymentResponse {
149 pub success: bool,
150 pub transaction: String,
151 pub network: String,
152 pub payer: String,
153}
154
155impl From<FacilitatorSettleSuccess> for PaymentResponse {
156 fn from(success: FacilitatorSettleSuccess) -> Self {
157 PaymentResponse {
158 success: true,
159 transaction: success.transaction,
160 network: success.network,
161 payer: success.payer,
162 }
163 }
164}
165
166#[derive(Debug, Clone, PartialEq, Eq)]
167pub struct Base64EncodedHeader(pub String);
168
169impl Serialize for Base64EncodedHeader {
170 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
171 where
172 S: serde::Serializer,
173 {
174 serializer.serialize_str(&self.0)
175 }
176}
177
178impl<'de> Deserialize<'de> for Base64EncodedHeader {
179 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
180 where
181 D: serde::Deserializer<'de>,
182 {
183 let s = String::deserialize(deserializer)?;
184 Ok(Base64EncodedHeader(s))
185 }
186}
187
188impl Display for Base64EncodedHeader {
189 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
190 write!(f, "{}", self.0)
191 }
192}
193
194impl TryFrom<PaymentPayload> for Base64EncodedHeader {
195 type Error = serde_json::Error;
196
197 fn try_from(value: PaymentPayload) -> Result<Self, Self::Error> {
198 let json = serde_json::to_string(&value)?;
199 let encoded = BASE64_STANDARD.encode(json);
200 Ok(Base64EncodedHeader(encoded))
201 }
202}
203
204impl TryFrom<Base64EncodedHeader> for PaymentPayload {
205 type Error = crate::errors::Error;
206
207 fn try_from(value: Base64EncodedHeader) -> Result<Self, Self::Error> {
208 let decoded_bytes = BASE64_STANDARD.decode(&value.0)?;
209 let json_str = String::from_utf8(decoded_bytes)?;
210 let payload = serde_json::from_str(&json_str)?;
211 Ok(payload)
212 }
213}
214
215impl TryFrom<PaymentResponse> for Base64EncodedHeader {
216 type Error = serde_json::Error;
217
218 fn try_from(value: PaymentResponse) -> Result<Self, Self::Error> {
219 let json = serde_json::to_string(&value)?;
220 let encoded = BASE64_STANDARD.encode(json);
221 Ok(Base64EncodedHeader(encoded))
222 }
223}
224
225impl TryFrom<Base64EncodedHeader> for PaymentResponse {
226 type Error = crate::errors::Error;
227
228 fn try_from(value: Base64EncodedHeader) -> Result<Self, Self::Error> {
229 let decoded_bytes = BASE64_STANDARD.decode(&value.0)?;
230 let json_str = String::from_utf8(decoded_bytes)?;
231 let response = serde_json::from_str(&json_str)?;
232 Ok(response)
233 }
234}