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}