Production-grade Elixir SDK for the Rapyd fintech-as-a-service platform.
Features
- Full API surface — Collect, Disburse, Wallet, Issuing, Partner, Webhook, Resource
- 178+ service methods across 7 domain-aligned service modules
- HMAC-SHA256 request signing — every request automatically authenticated
- Webhook verification — constant-time HMAC comparison, typed event structs, dispatch router
- Full-jitter exponential backoff — configurable retries on 429/5xx
- Structured errors — 17 semantic error types, retryability flag, operation ID
- Swappable HTTP client — inject a
Moxmock for zero-network tests - Full typespec coverage —
@specand@typeon all public APIs - Zero business-logic dependencies — only
reqandjason
Installation
def deps do
[
{:rapyd, "~> 1.0"}
]
endQuick Start
# Build a client (do this once at application start, store in your context/config)
client = Rapyd.new!(
access_key: System.fetch_env!("RAPYD_ACCESS_KEY"),
secret_key: System.fetch_env!("RAPYD_SECRET_KEY"),
sandbox: true # false for production
)
# Accept a payment
{: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"
}
}
})
IO.puts("Payment created: #{payment["id"]} status=#{payment["status"]}")Configuration
client = Rapyd.new!(
access_key: "your_access_key", # required
secret_key: "your_secret_key", # required
sandbox: true, # default: true
max_retries: 4, # default: 4 (1 = no retries)
timeout: 30_000, # default: 30 000 ms
http_client: Rapyd.HTTP.Client # default; swap for tests
)Services
Collect
alias Rapyd.Services.Collect
# Payments
{:ok, payment} = Collect.create_payment(client, params)
{:ok, payment} = Collect.get_payment(client, "pay_id")
{:ok, payments} = Collect.list_payments(client, %{currency: "USD"})
{:ok, payment} = Collect.capture_payment(client, "pay_id")
{:ok, _} = Collect.cancel_payment(client, "pay_id")
# Hosted checkout
{:ok, page} = Collect.create_checkout_page(client, params)
# Refunds
{:ok, refund} = Collect.create_refund(client, %{payment: "pay_id", amount: 25})
# Customers & subscriptions
{:ok, customer} = Collect.create_customer(client, %{email: "user@example.com"})
{:ok, plan} = Collect.create_plan(client, params)
{:ok, sub} = Collect.create_subscription(client, %{customer: "cus_id", plan: "plan_id"})Disburse
alias Rapyd.Services.Disburse
{:ok, beneficiary} = Disburse.create_beneficiary(client, params)
{:ok, payout} = Disburse.create_payout(client, params)
{:ok, payout} = Disburse.confirm_payout(client, "payout_id")
{:ok, methods} = Disburse.list_payout_method_types(client, %{sender_country: "US"})Wallet
alias Rapyd.Services.Wallet
{:ok, wallet} = Wallet.create_wallet(client, %{type: "person", first_name: "Ada"})
{:ok, _} = Wallet.change_wallet_status(client, "ew_id", "disable")
{:ok, contact} = Wallet.create_contact(client, "ew_id", params)
{:ok, txns} = Wallet.list_wallet_transactions(client, "ew_id", %{currency: "USD"})
{:ok, va} = Wallet.create_virtual_account(client, %{ewallet: "ew_id", country: "US"})
{:ok, ident} = Wallet.create_identity_verification(client, params)Issuing
alias Rapyd.Services.Issuing
{:ok, card} = Issuing.issue_card(client, %{card_program: "cp_id", ewallet_contact: "con_id"})
{:ok, card} = Issuing.activate_card(client, "card_id")
{:ok, card} = Issuing.block_card(client, "card_id")
{:ok, details} = Issuing.get_card_details(client, "card_id") # PCI scope
{:ok, txns} = Issuing.list_card_transactions(client, "card_id")Partner
alias Rapyd.Services.Partner
{:ok, org} = Partner.create_organization(client, params)
{:ok, app} = Partner.create_application(client, params)
{:ok, app} = Partner.submit_application(client, "app_id")
{:ok, account} = Partner.create_settlement_bank_account(client, params)Webhook Handling
Always verify the signature before trusting event data:
defmodule MyApp.WebhookController do
alias Rapyd.{Services.Webhook, Types.WebhookEvent}
def handle(conn) do
raw_body = conn.assigns[:raw_body]
headers = %{
salt: get_req_header(conn, "salt") |> List.first(),
timestamp: get_req_header(conn, "timestamp") |> List.first(),
signature: get_req_header(conn, "signature") |> List.first()
}
case Webhook.parse_and_verify(client, raw_body, headers) do
{:ok, event} ->
dispatch(event)
send_resp(conn, 200, "ok")
{:error, %Rapyd.Error{type: :webhook_signature}} ->
send_resp(conn, 401, "invalid signature")
end
end
defp dispatch(event) do
WebhookEvent.dispatch(event, %{
"PAYMENT_SUCCEEDED" => &handle_payment/1,
"PAYOUT_COMPLETED" => &handle_payout/1,
default: &log_event/1
})
end
endError Handling
case Rapyd.Services.Collect.create_payment(client, params) do
{:ok, payment} ->
{:ok, payment}
{:error, %Rapyd.Error{type: :insufficient_funds}} ->
{:error, :payment_method_declined}
{:error, %Rapyd.Error{type: :rate_limit, retryable?: true}} ->
Process.sleep(2_000)
retry(params)
{:error, %Rapyd.Error{type: :unauthorized}} ->
raise "Invalid Rapyd credentials — check RAPYD_ACCESS_KEY / RAPYD_SECRET_KEY"
{:error, %Rapyd.Error{} = err} ->
Logger.error("Rapyd API error",
type: err.type,
code: err.error_code,
http: err.status_code,
operation: err.operation_id
)
{:error, :rapyd_error}
endError types
| Type | HTTP | Retryable |
|---|---|---|
:payment_not_found | 404 | ✗ |
:payment_failed | 400 | ✗ |
:payment_canceled | 400 | ✗ |
:insufficient_funds | 400 | ✗ |
:card_declined | 400 | ✗ |
:expired_card | 400 | ✗ |
:invalid_card | 400 | ✗ |
:do_not_honor | 400 | ✗ |
:fraud | 400 | ✗ |
:rate_limit | 429 | ✓ |
:unauthorized | 401 | ✗ |
:forbidden | 403 | ✗ |
:not_found | 404 | ✗ |
:validation | — | ✗ |
:webhook_signature | — | ✗ |
:network | — | ✓ |
:timeout | — | ✓ |
:api_error / :unknown | 5xx | ✓ |
Testing
Inject a Mox mock to test without network calls:
# test/test_helper.exs
Mox.defmock(MyApp.MockHTTP, for: Rapyd.HTTP.Behaviour)
# in your test
client = Rapyd.new!(
access_key: "key",
secret_key: "secret",
http_client: MyApp.MockHTTP
)
MyApp.MockHTTP
|> expect(:request, fn _client, :post, "/v1/payments", _body, [] ->
{:ok, %{"id" => "pay_test", "status" => "ACT"}}
end)License
MIT — see LICENSE.