# `X402.Extensions.BuilderCode`
[🔗](https://github.com/cardotrejos/x402/blob/v0.9.0/lib/x402/extensions/builder_code.ex#L1)

The x402 `builder-code` extension: ERC-8021 on-chain attribution codes.

Implements the
[builder-code extension](https://github.com/x402-foundation/x402/blob/main/specs/extensions/builder_code.md).
A resource server declares the application's *app code* (`a`) — and
optionally up to 5 of its own *service codes* (`s`) — under
`PaymentRequired.extensions["builder-code"]` (`extension/2`). The client
echoes the declaration and attaches up to 5 service codes of its own
(`enricher/1`). At settlement the facilitator adds its *wallet code*
(`w`), CBOR-encodes `a`, `s`, and `w` as an ERC-8021 Schema 2 suffix, and
appends it to the settlement transaction calldata.

    # server (PaymentRequired.extensions)
    %{"builder-code" => %{"info" => %{"a" => "my_app"}, "schema" => %{...}}}

    # client (PaymentPayload.extensions)
    %{"builder-code" => %{"info" => %{"a" => "my_app", "s" => ["my_client"]}, "schema" => %{...}}}

Every code matches `^[a-z0-9_]{1,32}$` (`valid_code?/1`).

## What the resource server does with the code

Nothing beyond validation and forwarding: the codes travel inside the
`PaymentPayload.extensions` the gate already sends to the facilitator on
`POST /verify` and `POST /settle`, and the facilitator is the party that
encodes them into calldata. The resource server is, however, the
authority for `a`: `validate_echo/2` implements the spec's echo rules —
an echoed `a` must equal the advertised one (and must be absent when the
server declared none), every code must be well-formed, and the echoed
`s` may carry at most 10 entries (the combined client and server
reservations). `X402.Plug.PaymentGate` and `X402.MCP.Server` run these
rules on every payment whose payload carries the extension.

The echo may use either wire shape the ecosystem produces: the
`%{"info" => %{...}}` envelope the reference client emits, or the bare
`%{"a" => ..., "s" => ...}` map from the spec's examples.

# `code`

```elixir
@type code() :: String.t()
```

A builder code: 1–32 lowercase alphanumeric or underscore characters.

# `error`

```elixir
@type error() ::
  :invalid_builder_code_extension
  | {:invalid_builder_code, String.t()}
  | :too_many_service_codes
  | :builder_code_mismatch
```

Errors returned by `extract/1` and `validate_echo/2`.

# `extracted`

```elixir
@type extracted() :: %{app_code: code() | nil, service_codes: [code()]}
```

Codes extracted from an echoed `builder-code` value.

# `enricher`
*since 0.9.0* 

```elixir
@spec enricher(keyword()) :: (map(), map() | nil -&gt; {:ok, map()})
```

Builds a client-side enricher for `X402.Client.build_payment/3`'s
`:extensions` option.

The returned function attaches the client's service codes as
`extensions["builder-code"]["info"]["s"]`. When the server advertised
`builder-code`, the advertised `info` (including `a`) and `schema` are
echoed unchanged and the client codes are prepended to any server codes
(deduplicated, client first, as the reference client merges them). When
it did not, only `%{"info" => %{"s" => codes}}` is attached — never `a`.

## Options

* `:service_codes` - Required. The client's service code(s) (`s`): a code or a list of at most
  5 codes.

* `:always` (`t:boolean/0`) - Attach `s` even when the server did not advertise `builder-code`, as
  the spec's client behaviour prescribes. With `false` the enricher is a
  no-op for servers that do not declare the extension. The default value is `true`.

## Examples

    iex> enricher = X402.Extensions.BuilderCode.enricher(service_codes: "my_client")
    iex> advertised = %{"builder-code" => X402.Extensions.BuilderCode.extension("my_app", service_codes: "sdk")}
    iex> {:ok, enriched} = enricher.(%{"extensions" => advertised}, %{"extensions" => advertised})
    iex> enriched["extensions"]["builder-code"]["info"]
    %{"a" => "my_app", "s" => ["my_client", "sdk"]}

    iex> enricher = X402.Extensions.BuilderCode.enricher(service_codes: ["base_mcp", "demo_app"])
    iex> {:ok, enriched} = enricher.(%{"extensions" => %{}}, %{"extensions" => %{}})
    iex> enriched["extensions"]["builder-code"]
    %{"info" => %{"s" => ["base_mcp", "demo_app"]}}

    iex> enricher = X402.Extensions.BuilderCode.enricher(service_codes: "my_client", always: false)
    iex> enricher.(%{"extensions" => %{}}, %{"extensions" => %{}})
    {:ok, %{"extensions" => %{}}}

# `extension`
*since 0.9.0* 

```elixir
@spec extension(
  code(),
  keyword()
) :: map()
```

Builds the server-side advertisement for `PaymentRequired.extensions`.

Raises `NimbleOptions.ValidationError` for a malformed app code or
service codes: declaring an invalid code is a configuration error the
spec requires rejecting at declaration time.

## Options

* `:service_codes` - The server's own service code(s) (`info.s`): a code or a list of at
  most 5 codes. The default value is `[]`.

## Examples

    iex> X402.Extensions.BuilderCode.extension("my_app")["info"]
    %{"a" => "my_app"}

    iex> X402.Extensions.BuilderCode.extension("my_app", service_codes: "sdk_elixir")["info"]
    %{"a" => "my_app", "s" => ["sdk_elixir"]}

    iex> extension = X402.Extensions.BuilderCode.extension("my_app")
    iex> extension["schema"] == X402.Extensions.BuilderCode.schema()
    true

# `extension_key`
*since 0.9.0* 

```elixir
@spec extension_key() :: String.t()
```

Returns the extension key on the wire.

## Examples

    iex> X402.Extensions.BuilderCode.extension_key()
    "builder-code"

# `extract`
*since 0.9.0* 

```elixir
@spec extract(term()) :: {:ok, extracted() | nil} | {:error, error()}
```

Extracts the app code and service codes from a `builder-code` value.

Accepts the value as it appears under `extensions["builder-code"]` in a
`PaymentPayload` (or `PaymentRequired`): either the `%{"info" => ...}`
envelope or a bare code map. `s` may be a single code or a list; it is
always returned as a list. Returns `{:ok, nil}` for `nil`.

Codes are checked for format only. The count of `s` entries is **not**
checked here — see `validate_echo/2` for the echo rules.

## Examples

    iex> X402.Extensions.BuilderCode.extract(%{"info" => %{"a" => "my_app", "s" => "my_client"}})
    {:ok, %{app_code: "my_app", service_codes: ["my_client"]}}

    iex> X402.Extensions.BuilderCode.extract(%{"s" => ["base_mcp", "demo_app"]})
    {:ok, %{app_code: nil, service_codes: ["base_mcp", "demo_app"]}}

    iex> X402.Extensions.BuilderCode.extract(%{"info" => %{"a" => "My App"}})
    {:error, {:invalid_builder_code, "a"}}

    iex> X402.Extensions.BuilderCode.extract(%{"info" => %{"s" => [1]}})
    {:error, {:invalid_builder_code, "s"}}

    iex> X402.Extensions.BuilderCode.extract("my_app")
    {:error, :invalid_builder_code_extension}

    iex> X402.Extensions.BuilderCode.extract(nil)
    {:ok, nil}

# `schema`
*since 0.9.0* 

```elixir
@spec schema() :: map()
```

Returns the JSON schema the server advertises for the extension.

## Examples

    iex> schema = X402.Extensions.BuilderCode.schema()
    iex> schema["properties"]["a"]["pattern"]
    "^[a-z0-9_]{1,32}$"
    iex> schema["properties"]["s"]["maxItems"]
    11

# `valid_code?`
*since 0.9.0* 

```elixir
@spec valid_code?(term()) :: boolean()
```

Checks whether a value is a well-formed builder code.

## Examples

    iex> X402.Extensions.BuilderCode.valid_code?("my_app_1")
    true

    iex> X402.Extensions.BuilderCode.valid_code?("My-App")
    false

    iex> X402.Extensions.BuilderCode.valid_code?("")
    false

    iex> X402.Extensions.BuilderCode.valid_code?(String.duplicate("a", 33))
    false

    iex> X402.Extensions.BuilderCode.valid_code?(:my_app)
    false

# `validate_echo`
*since 0.9.0* 

```elixir
@spec validate_echo(term(), term()) :: :ok | {:error, error()}
```

Validates a client's echoed `builder-code` value against the advertised
one, as the resource server must before forwarding a payment.

Both arguments are the values under `extensions["builder-code"]` (`nil`
when absent). The rules, from the spec:

* every echoed code must be well-formed (`{:invalid_builder_code, field}`);
* an echoed `a` must equal the advertised `info.a`, and must be absent
  when the server declared none (`:builder_code_mismatch`);
* the echoed `s` may carry at most 10 entries —
  the client and server reservations combined (`:too_many_service_codes`).

A `nil` echo is always valid: omitting the extension is allowed.

## Examples

    iex> advertised = X402.Extensions.BuilderCode.extension("my_app")
    iex> X402.Extensions.BuilderCode.validate_echo(%{"info" => %{"a" => "my_app", "s" => ["c"]}}, advertised)
    :ok

    iex> advertised = X402.Extensions.BuilderCode.extension("my_app")
    iex> X402.Extensions.BuilderCode.validate_echo(%{"a" => "other_app"}, advertised)
    {:error, :builder_code_mismatch}

    iex> X402.Extensions.BuilderCode.validate_echo(%{"a" => "my_app"}, nil)
    {:error, :builder_code_mismatch}

    iex> X402.Extensions.BuilderCode.validate_echo(%{"s" => "my_client"}, nil)
    :ok

    iex> too_many = Enum.map(1..11, &"code_#{&1}")
    iex> X402.Extensions.BuilderCode.validate_echo(%{"s" => too_many}, nil)
    {:error, :too_many_service_codes}

    iex> X402.Extensions.BuilderCode.validate_echo(nil, nil)
    :ok

---

*Consult [api-reference.md](api-reference.md) for complete listing*
