# `Rapyd`
[🔗](https://github.com/iamkanishka/rapyd/blob/v1.0.0/lib/rapyd.ex#L1)

Production-grade Elixir SDK for the [Rapyd](https://www.rapyd.net/)
fintech-as-a-service platform.

## Quick Start

    client = Rapyd.new!(
      access_key: System.fetch_env!("RAPYD_ACCESS_KEY"),
      secret_key: System.fetch_env!("RAPYD_SECRET_KEY"),
      sandbox: true
    )

    {:ok, payment} = Rapyd.Services.Collect.create_payment(client, %{
      amount: 100.00,
      currency: "USD",
      payment_method: %{
        type: "us_visa_card",
        fields: %{
          number: "4111111111111111",
          expiration_month: "12",
          expiration_year: "2026",
          cvv: "123"
        }
      }
    })

## Services

All API interaction is routed through domain-aligned service modules:

| Service | Description |
|---|---|
| `Rapyd.Services.Collect` | Accept payments, refunds, subscriptions, customers |
| `Rapyd.Services.Disburse` | Send payouts to beneficiaries worldwide |
| `Rapyd.Services.Wallet` | Manage eWallets, contacts, virtual accounts, KYC |
| `Rapyd.Services.Issuing` | Issue and manage physical and virtual cards |
| `Rapyd.Services.Partner` | PayFac / KYB onboarding for sub-merchants |
| `Rapyd.Services.Webhook` | Verify and route incoming Rapyd webhook events |
| `Rapyd.Services.Resource` | Reference data: FX rates, countries, currencies |

## Error Handling

All API calls return `{:ok, result}` or `{:error, %Rapyd.Error{}}`.

    case Rapyd.Services.Collect.create_payment(client, req) do
      {:ok, payment} ->
        IO.inspect(payment.id)

      {:error, %Rapyd.Error{type: :insufficient_funds}} ->
        # prompt customer for another payment method

      {:error, %Rapyd.Error{type: :rate_limit}} ->
        # back off and retry

      {:error, %Rapyd.Error{} = err} ->
        Logger.error("payment failed", code: err.error_code, op: err.operation_id)
    end

## Configuration

Options accepted by `new/1` and `new!/1`:

| Option | Type | Default | Description |
|---|---|---|---|
| `:access_key` | `String.t()` | required | Rapyd access key |
| `:secret_key` | `String.t()` | required | Rapyd secret key |
| `:sandbox` | `boolean()` | `true` | Use sandbox (`true`) or production (`false`) |
| `:base_url` | `String.t()` | auto | Override the API base URL |
| `:max_retries` | `non_neg_integer()` | `4` | Max request attempts (1 = no retries) |
| `:timeout` | `non_neg_integer()` | `30_000` | Request timeout in milliseconds |
| `:http_client` | module | `Rapyd.HTTP.Client` | Swappable HTTP client module |

# `new`

```elixir
@spec new(keyword()) :: {:ok, Rapyd.Client.t()} | {:error, String.t()}
```

Builds a new `Rapyd.Client` from the given options.

Returns `{:ok, client}` or `{:error, reason}`.

## Examples

    {:ok, client} = Rapyd.new(
      access_key: "your_key",
      secret_key: "your_secret",
      sandbox: true
    )

# `new!`

```elixir
@spec new!(keyword()) :: Rapyd.Client.t()
```

Builds a new `Rapyd.Client` from the given options, raising on error.

## Examples

    client = Rapyd.new!(
      access_key: System.fetch_env!("RAPYD_ACCESS_KEY"),
      secret_key: System.fetch_env!("RAPYD_SECRET_KEY")
    )

# `version`

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

Returns the SDK version string.

---

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