# `MPP.Intents.Charge`
[🔗](https://github.com/ZenHive/mpp/blob/v0.10.0/lib/mpp/intents/charge.ex#L1)

Charge intent request schema — the "Intent = Schema" half of MPP.

Defines the shared payment request structure used by all payment methods.
A charge intent specifies what needs to be paid (amount, currency) and
optional metadata (recipient, description, external ID).

The struct uses Elixir snake_case conventions internally. Use `to_request/1`
and `from_request/1` to convert to/from the spec's camelCase JSON format.

## Fields

  * `amount` — (required) string in base units (cents for fiat, wei for ETH). Never a float.
  * `currency` — (required) lowercase string (ISO 4217 for fiat, token address for on-chain)
  * `recipient` — (optional) payment recipient identifier
  * `description` — (optional) human-readable description
  * `external_id` — (optional) caller-provided correlation ID
  * `method_details` — (optional) method-specific fields (e.g., Stripe's `networkId`)

## API Functions
| Function | Arity | Description | Param Kinds |
| --- | --- | --- | --- |
| `from_request` | 1 | Deserialize a camelCase JSON map back into a charge intent struct. | `map: value` |
| `to_request` | 1 | Serialize the charge intent to a JSON-compatible map with camelCase keys per spec. | `charge: value` |
| `new` | 1 | Create a new charge intent with validation. Amount must be a string, currency is normalized to lowercase. | `opts: value` |

# `t`

```elixir
@type t() :: %MPP.Intents.Charge{
  amount: String.t(),
  currency: String.t(),
  description: String.t() | nil,
  external_id: String.t() | nil,
  method_details: map() | nil,
  recipient: String.t() | nil
}
```

# `from_request`

```elixir
@spec from_request(map()) :: {:ok, t()} | {:error, atom()}
@spec from_request(term()) :: {:error, :missing_required_fields}
```

Deserialize a camelCase JSON map back into a charge intent struct.

## Parameters

  * `map` - Map with camelCase string keys (from JSON-decoded challenge request) (value)

## Returns

`{:ok, charge}` on success, `{:error, reason}` on failure (`tagged_tuple`)

## Errors

  * `:amount_required`
  * `:invalid_amount`
  * `:currency_required`
  * `:invalid_currency`
  * `:missing_required_fields`

## Composes With

  * `new`
  * `to_request`

```elixir
# descripex:contract
%{
  params: %{
    map: %{
      description: "Map with camelCase string keys (from JSON-decoded challenge request)",
      kind: :value
    }
  },
  errors: [:amount_required, :invalid_amount, :currency_required,
   :invalid_currency, :missing_required_fields],
  returns: %{
    type: :tagged_tuple,
    description: "`{:ok, charge}` on success, `{:error, reason}` on failure"
  },
  composes_with: [:new, :to_request]
}
```

# `new`

```elixir
@spec new(keyword()) :: {:ok, t()} | {:error, atom()}
```

Create a new charge intent with validation. Amount must be a string, currency is normalized to lowercase.

## Parameters

  * `opts` - Keyword list with `:amount` (required string), `:currency` (required string), `:recipient`, `:description`, `:external_id`, `:method_details` (all optional) (value)

## Returns

`{:ok, charge}` on success, `{:error, reason}` on failure (`tagged_tuple`)

## Errors

  * `:amount_required`
  * `:invalid_amount`
  * `:currency_required`
  * `:invalid_currency`

## Composes With

  * `to_request`

```elixir
# descripex:contract
%{
  params: %{
    opts: %{
      description: "Keyword list with `:amount` (required string), `:currency` (required string), `:recipient`, `:description`, `:external_id`, `:method_details` (all optional)",
      kind: :value
    }
  },
  errors: [:amount_required, :invalid_amount, :currency_required,
   :invalid_currency],
  returns: %{
    type: :tagged_tuple,
    description: "`{:ok, charge}` on success, `{:error, reason}` on failure"
  },
  composes_with: [:to_request]
}
```

# `to_request`

```elixir
@spec to_request(t()) :: map()
```

Serialize the charge intent to a JSON-compatible map with camelCase keys per spec.

## Parameters

  * `charge` - Charge struct to serialize (value)

## Returns

Map with camelCase string keys for JSON encoding into challenge `request` (`map`)

## Composes With

  * `new`
  * `from_request`

```elixir
# descripex:contract
%{
  params: %{charge: %{description: "Charge struct to serialize", kind: :value}},
  returns: %{
    type: :map,
    description: "Map with camelCase string keys for JSON encoding into challenge `request`"
  },
  composes_with: [:new, :from_request]
}
```

---

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