A production-grade Elixir client for the Ramp Developer API (v1).

Ramp is dependency-light by design: it uses Erlang/OTP's built-in :httpc/:ssl for HTTP and Jason for JSON, so adding it to a project doesn't drag in an HTTP client stack. It covers the full Ramp API surface: cards, users, transactions, spend limits, bills, vendors, merchants, entities, departments, locations, statements, cashbacks, spend programs, reimbursements, audit logs, accounting sync, and webhooks -- with OAuth2 token management, automatic retries, cursor-based pagination as lazy Streams, deferred-task polling, and webhook signature verification all built in.

Installation

Add :ramp to your mix.exs dependencies:

def deps do
  [
    {:ramp, "~> 0.1"}
  ]
end

Quick start

client =
  Ramp.Client.new(
    client_id: System.fetch_env!("RAMP_CLIENT_ID"),
    client_secret: System.fetch_env!("RAMP_CLIENT_SECRET"),
    scopes: ~w(transactions:read cards:read cards:write users:read)
  )

{:ok, card} = Ramp.Cards.get(client, "crd_1a2b3c")

client
|> Ramp.Transactions.list(state: "CLEARED")
|> Stream.take(50)
|> Enum.each(&IO.inspect/1)

See Ramp.Client.new/1 for every way to authenticate (client credentials, a pre-obtained access token, or a supervised Ramp.TokenManager for production deployments).

Resource modules

Every resource follows the same shape: a list/2 returning a lazy, auto-paginating Stream; a get/2; and whatever writes the resource supports (create/*, update/*, delete/2, or domain-specific actions like Ramp.Cards.suspend/2).

Errors

Every operation returns {:ok, result} or {:error, %Ramp.Error{}}. Ramp.Error normalizes every failure mode -- HTTP error responses, network failures, timeouts, deferred-task failures -- into one struct with a :type you can pattern-match on; see Ramp.Error for the full list of predicate helpers (not_found?/1, rate_limited?/1, etc).

Pagination

List endpoints return a Stream (see Ramp.Pagination) that fetches pages lazily as you enumerate it -- Enum.take/2, Stream.filter/2, Enum.find/2, and friends all "just work" without over-fetching.

Async writes

Some writes (card/user/limit creation) are asynchronous on Ramp's side. The corresponding create/* functions block and poll to completion by default (see Ramp.Poller); pass poll: false to instead get a Ramp.DeferredTaskRef back immediately.

Webhooks

See Ramp.Webhooks to verify and decode inbound webhook deliveries, and Ramp.WebhookSubscriptions to manage which events get delivered where.