# `MPP.Intents.Session`
[🔗](https://github.com/ZenHive/mpp/blob/v0.16.0/lib/mpp/intents/session.ex#L1)

Session intent request schema — the "Intent = Schema" half of MPP for
pay-as-you-go / metered sessions.

Defines the shared session payment request structure used by all payment
methods that support the `"session"` intent. A session intent specifies a
per-unit rate (`amount`), optional unit type, currency, and optional deposit
guidance for opening a payment channel.

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
(matching mpp-rs `SessionRequest`). `decimals` and `external_id` are transient
and are never serialized into the request map.

Wire shape (mpp-rs `SessionRequest`): `amount`, `currency`, optional
`unitType` / `recipient` / `suggestedDeposit` / `methodDetails`. Transient
fields `decimals` and `external_id` are never serialized (mpp-rs has no
`externalId` on session requests; `decimals` is `#[serde(skip)]`).

## Fields

  * `amount` — (required) per-unit rate in base units (string). Never a float.
  * `currency` — (required) string, preserved verbatim (ISO 4217 for fiat, token address for on-chain)
  * `unit_type` — (optional) rate unit, e.g. `"second"`, `"minute"`, `"request"`
  * `recipient` — (optional) payment recipient identifier
  * `suggested_deposit` — (optional) suggested channel deposit in base units
  * `decimals` — (optional, transient) token decimals for human-readable → base-unit conversion;
    stripped from wire serialization (mpp-rs `#[serde(skip)]`)
  * `external_id` — (optional, transient) caller-provided correlation ID; not on the wire
    (unlike charge intent — mpp-rs `SessionRequest` has no `externalId`)
  * `method_details` — (optional) method-specific fields

## API Functions
| Function | Arity | Description | Param Kinds |
| --- | --- | --- | --- |
| `from_request` | 1 | Deserialize a camelCase JSON map back into a session intent struct. | `map: value` |
| `to_request` | 1 | Serialize the session intent to a JSON-compatible map with camelCase keys per mpp-rs SessionRequest. | `session: value` |
| `new` | 1 | Create a new session intent with validation. Amount and currency must be strings; currency is preserved verbatim. | `opts: value` |

# `t`

```elixir
@type t() :: %MPP.Intents.Session{
  amount: String.t(),
  currency: String.t(),
  decimals: non_neg_integer() | nil,
  external_id: String.t() | nil,
  method_details: map() | nil,
  recipient: String.t() | nil,
  suggested_deposit: String.t() | nil,
  unit_type: 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 session intent struct.

## Parameters

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

## Returns

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

## Errors

  * `:amount_required`
  * `:invalid_amount`
  * `:currency_required`
  * `:invalid_currency`
  * `:invalid_field_type`
  * `: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, :invalid_field_type, :missing_required_fields],
  returns: %{
    type: :tagged_tuple,
    description: "`{:ok, session}` on success, `{:error, reason}` on failure"
  },
  composes_with: [:new, :to_request]
}
```

# `new`

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

Create a new session intent with validation. Amount and currency must be strings; currency is preserved verbatim.

## Parameters

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

## Returns

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

## Errors

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

## Composes With

  * `to_request`

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

# `to_request`

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

Serialize the session intent to a JSON-compatible map with camelCase keys per mpp-rs SessionRequest.

## Parameters

  * `session` - Session struct to serialize (value)

## Returns

Map with camelCase string keys for JSON encoding into challenge `request` (transient `decimals`/`external_id` omitted) (`map`)

## Composes With

  * `new`
  * `from_request`

```elixir
# descripex:contract
%{
  params: %{
    session: %{description: "Session struct to serialize", kind: :value}
  },
  returns: %{
    type: :map,
    description: "Map with camelCase string keys for JSON encoding into challenge `request` (transient `decimals`/`external_id` omitted)"
  },
  composes_with: [:new, :from_request]
}
```

---

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