Skip to main content

r402_core/wire/
payment_payload.rs

1//! Buyer-signed payment authorization.
2
3use serde::{Deserialize, Serialize};
4
5use super::{Extensions, ResourceInfo, Version2};
6
7/// A signed payment authorization sent by the buyer to the seller.
8///
9/// In x402 v2 the payload is self-describing: it carries the `accepted`
10/// requirements the buyer chose (so the facilitator can re-verify them)
11/// plus the scheme-specific `payload`, an optional resource descriptor,
12/// and an optional `extensions` map.
13#[derive(Debug, Clone, Serialize, Deserialize)]
14#[serde(rename_all = "camelCase", deny_unknown_fields)]
15#[non_exhaustive]
16pub struct PaymentPayload<TAccepted, TPayload> {
17    /// The terms the buyer accepted (a full [`super::PaymentRequirements`] form).
18    pub accepted: TAccepted,
19    /// Scheme-specific signed payload (e.g., EIP-3009 authorization).
20    pub payload: TPayload,
21    /// Optional resource metadata copied from the 402 response.
22    #[serde(default, skip_serializing_if = "Option::is_none")]
23    pub resource: Option<ResourceInfo>,
24    /// Protocol version marker (always `2`).
25    pub x402_version: Version2,
26    /// Optional extension payload block.
27    #[serde(default, skip_serializing_if = "Extensions::is_empty")]
28    pub extensions: Extensions,
29}
30
31impl<TAccepted, TPayload> PaymentPayload<TAccepted, TPayload> {
32    /// Constructs a payload from the two required fields. Use the
33    /// [`Self::with_resource`] / [`Self::with_extensions`] builders to
34    /// attach the optional blocks.
35    #[must_use]
36    pub fn new(accepted: TAccepted, payload: TPayload) -> Self {
37        Self {
38            accepted,
39            payload,
40            resource: None,
41            x402_version: super::V2,
42            extensions: Extensions::new(),
43        }
44    }
45
46    /// Builder: attaches optional resource metadata.
47    #[must_use]
48    pub fn with_resource(mut self, resource: ResourceInfo) -> Self {
49        self.resource = Some(resource);
50        self
51    }
52
53    /// Builder: attaches an optional resource (passes through `None`
54    /// untouched, useful when the value is produced via `Option::map`).
55    #[must_use]
56    pub fn with_optional_resource(mut self, resource: Option<ResourceInfo>) -> Self {
57        self.resource = resource;
58        self
59    }
60
61    /// Builder: replaces the `extensions` block.
62    #[must_use]
63    pub fn with_extensions(mut self, extensions: Extensions) -> Self {
64        self.extensions = extensions;
65        self
66    }
67}