Skip to main content

r402_http/
headers.rs

1//! HTTP header encoding and decoding for x402 protocol messages.
2//!
3//! Handles Base64-encoded JSON payloads in `PAYMENT-SIGNATURE`,
4//! `PAYMENT-REQUIRED`, `PAYMENT-RESPONSE`, and legacy `X-PAYMENT` headers.
5//!
6//! Corresponds to Python SDK's `http/x402_http_client_base.py`.
7
8use base64::prelude::*;
9use r402::proto::helpers::{PaymentPayloadEnum, PaymentRequiredEnum};
10use r402::{PaymentPayload, PaymentPayloadV1, PaymentRequired, PaymentRequiredV1, SettleResponse};
11
12use crate::error::HttpError;
13
14/// Encodes a V2 [`PaymentPayload`] as a Base64 string for the
15/// `PAYMENT-SIGNATURE` header.
16///
17/// # Errors
18///
19/// Returns [`HttpError::Serialize`] if JSON serialization fails.
20pub fn encode_payment_signature(payload: &PaymentPayload) -> Result<String, HttpError> {
21    let json = serde_json::to_vec(payload)?;
22    Ok(BASE64_STANDARD.encode(&json))
23}
24
25/// Encodes a V1 [`PaymentPayloadV1`] as a Base64 string for the
26/// `X-PAYMENT` header.
27///
28/// # Errors
29///
30/// Returns [`HttpError::Serialize`] if JSON serialization fails.
31pub fn encode_x_payment(payload: &PaymentPayloadV1) -> Result<String, HttpError> {
32    let json = serde_json::to_vec(payload)?;
33    Ok(BASE64_STANDARD.encode(&json))
34}
35
36/// Decodes a `PAYMENT-SIGNATURE` or `X-PAYMENT` header value into a
37/// version-tagged payload enum.
38///
39/// Attempts V2 first, then falls back to V1.
40///
41/// # Errors
42///
43/// Returns [`HttpError`] on Base64 or JSON decode failure.
44pub fn decode_payment_payload(header_value: &str) -> Result<PaymentPayloadEnum, HttpError> {
45    let bytes = BASE64_STANDARD.decode(header_value.trim())?;
46    let value: serde_json::Value = serde_json::from_slice(&bytes)?;
47    r402::proto::helpers::parse_payment_payload(&value).map_err(HttpError::Protocol)
48}
49
50/// Encodes a [`PaymentRequired`] (V2) as a Base64 string for the
51/// `PAYMENT-REQUIRED` header.
52///
53/// # Errors
54///
55/// Returns [`HttpError::Serialize`] if JSON serialization fails.
56pub fn encode_payment_required(required: &PaymentRequired) -> Result<String, HttpError> {
57    let json = serde_json::to_vec(required)?;
58    Ok(BASE64_STANDARD.encode(&json))
59}
60
61/// Encodes a [`PaymentRequiredV1`] as a Base64 string for the
62/// `PAYMENT-REQUIRED` header (V1).
63///
64/// # Errors
65///
66/// Returns [`HttpError::Serialize`] if JSON serialization fails.
67pub fn encode_payment_required_v1(required: &PaymentRequiredV1) -> Result<String, HttpError> {
68    let json = serde_json::to_vec(required)?;
69    Ok(BASE64_STANDARD.encode(&json))
70}
71
72/// Decodes a `PAYMENT-REQUIRED` header value into a version-tagged enum.
73///
74/// # Errors
75///
76/// Returns [`HttpError`] on Base64 or JSON decode failure.
77pub fn decode_payment_required(header_value: &str) -> Result<PaymentRequiredEnum, HttpError> {
78    let bytes = BASE64_STANDARD.decode(header_value.trim())?;
79    let value: serde_json::Value = serde_json::from_slice(&bytes)?;
80    r402::proto::helpers::parse_payment_required(&value).map_err(HttpError::Protocol)
81}
82
83/// Encodes a [`SettleResponse`] as a Base64 string for the
84/// `PAYMENT-RESPONSE` header.
85///
86/// # Errors
87///
88/// Returns [`HttpError::Serialize`] if JSON serialization fails.
89pub fn encode_payment_response(response: &SettleResponse) -> Result<String, HttpError> {
90    let json = serde_json::to_vec(response)?;
91    Ok(BASE64_STANDARD.encode(&json))
92}
93
94/// Decodes a `PAYMENT-RESPONSE` header value into a [`SettleResponse`].
95///
96/// # Errors
97///
98/// Returns [`HttpError`] on Base64 or JSON decode failure.
99pub fn decode_payment_response(header_value: &str) -> Result<SettleResponse, HttpError> {
100    let bytes = BASE64_STANDARD.decode(header_value.trim())?;
101    Ok(serde_json::from_slice(&bytes)?)
102}