Skip to main content

r402_core/wire/
payment_required.rs

1//! HTTP 402 response body.
2
3use compact_str::CompactString;
4use serde::{Deserialize, Serialize};
5
6use super::{Extensions, PaymentRequirements, ResourceInfo, Version2};
7
8/// Body of an HTTP 402 "Payment Required" response.
9///
10/// Contains:
11///
12/// - the x402 version marker,
13/// - an optional human-readable `error` string for malformed clients,
14/// - resource metadata,
15/// - the list of [`PaymentRequirements`] the seller will accept, and
16/// - an optional `extensions` block.
17#[derive(Debug, Clone, Serialize, Deserialize)]
18#[serde(rename_all = "camelCase", deny_unknown_fields)]
19#[non_exhaustive]
20pub struct PaymentRequired {
21    /// Protocol version (always `2`).
22    pub x402_version: Version2,
23    /// Optional error message describing why the request was rejected.
24    #[serde(default, skip_serializing_if = "Option::is_none")]
25    pub error: Option<CompactString>,
26    /// Resource metadata.
27    pub resource: ResourceInfo,
28    /// Accepted payment terms.
29    #[serde(default)]
30    pub accepts: Vec<PaymentRequirements>,
31    /// Optional extension block.
32    #[serde(default, skip_serializing_if = "Extensions::is_empty")]
33    pub extensions: Extensions,
34}
35
36impl PaymentRequired {
37    /// Constructs a 402 body with the resource block and an empty
38    /// `accepts` list. Use [`Self::with_accepts`] to attach payment
39    /// requirements and [`Self::with_error`] to surface a diagnostic
40    /// message to malformed clients.
41    #[must_use]
42    pub fn new(resource: ResourceInfo) -> Self {
43        Self {
44            x402_version: super::V2,
45            error: None,
46            resource,
47            accepts: Vec::new(),
48            extensions: Extensions::new(),
49        }
50    }
51
52    /// Builder: replaces the accepted payment requirements list.
53    #[must_use]
54    pub fn with_accepts(mut self, accepts: Vec<PaymentRequirements>) -> Self {
55        self.accepts = accepts;
56        self
57    }
58
59    /// Builder: appends a single payment requirement to the `accepts` list.
60    #[must_use]
61    pub fn add_accept(mut self, accept: PaymentRequirements) -> Self {
62        self.accepts.push(accept);
63        self
64    }
65
66    /// Builder: attaches a human-readable error message describing why the
67    /// request was rejected (e.g. `"missing X-PAYMENT header"`).
68    #[must_use]
69    pub fn with_error(mut self, error: impl Into<CompactString>) -> Self {
70        self.error = Some(error.into());
71        self
72    }
73
74    /// Builder: replaces the `extensions` block.
75    #[must_use]
76    pub fn with_extensions(mut self, extensions: Extensions) -> Self {
77        self.extensions = extensions;
78        self
79    }
80}