Skip to main content

Elixir Library (omise-elixir)

The omise-elixir library provides an idiomatic Elixir interface to the Omise API with pattern matching, OTP features, and excellent Phoenix integration.

Installationโ€‹

Using Mixโ€‹

Add to your mix.exs:

def deps do
[
{:omise, "~> 0.11"}
]
end

Then run:

mix deps.get

Requirementsโ€‹

  • Elixir 1.10 or higher (including Elixir 1.14+)
  • Erlang/OTP 22+ (including OTP 25+)
  • Mix for dependency management
  • Phoenix 1.6+ (optional, for Phoenix applications)

Quick Startโ€‹

Basic Configurationโ€‹

# Configure your API keys
Omise.configure(
public_key: "pkey_test_123456789",
secret_key: "skey_test_123456789",
api_version: "2019-05-29"
)

Phoenix Configurationโ€‹

# config/config.exs
config :omise,
public_key: System.get_env("OMISE_PUBLIC_KEY"),
secret_key: System.get_env("OMISE_SECRET_KEY"),
api_version: "2019-05-29"

# config/runtime.exs (Phoenix 1.6+)
import Config

config :omise,
public_key: System.fetch_env!("OMISE_PUBLIC_KEY"),
secret_key: System.fetch_env!("OMISE_SECRET_KEY")

Environment Variablesโ€‹

# Development/Test
export OMISE_SECRET_KEY=skey_test_123456789
export OMISE_PUBLIC_KEY=pkey_test_123456789

# Production
# export OMISE_SECRET_KEY=skey_live_123456789
# export OMISE_PUBLIC_KEY=pkey_live_123456789

Common Operationsโ€‹

Creating a Chargeโ€‹

# Create a charge with a card token
{:ok, charge} = Omise.Charge.create(
amount: 100_000, # 1,000.00 THB (in smallest currency unit)
currency: "THB",
card: "tokn_test_123",
description: "Order #1234",
metadata: %{
order_id: "1234",
customer_name: "John Doe"
}
)

case charge do
%{paid: true} ->
IO.puts("Charge successful: #{charge.id}")
%{paid: false} ->
IO.puts("Charge failed: #{charge.failure_message}")
end

With Pattern Matchingโ€‹

defmodule PaymentService do
def create_charge(token, amount) do
case Omise.Charge.create(amount: amount, currency: "THB", card: token) do
{:ok, %{paid: true} = charge} ->
{:ok, charge}

{:ok, %{paid: false, failure_message: message}} ->
{:error, message}

{:error, error} ->
{:error, error}
end
end
end

With 3D Secureโ€‹

def create_secure_charge(token, amount, return_uri) do
case Omise.Charge.create(
amount: amount,
currency: "THB",
card: token,
return_uri: return_uri
) do
{:ok, %{authorized: true, authorize_uri: uri} = charge} when not is_nil(uri) ->
{:redirect, uri}

{:ok, %{authorized: true, paid: true} = charge} ->
{:success, charge}

{:ok, %{failure_message: message}} ->
{:error, message}

{:error, error} ->
{:error, error}
end
end

Retrieving a Chargeโ€‹

case Omise.Charge.retrieve("chrg_test_123") do
{:ok, charge} ->
IO.puts("Amount: #{charge.amount}")
IO.puts("Currency: #{charge.currency}")
IO.puts("Status: #{charge.status}")
IO.puts("Paid: #{charge.paid}")

{:error, error} ->
IO.puts("Error: #{inspect(error)}")
end

Listing Chargesโ€‹

# List all charges with pagination
{:ok, charges} = Omise.Charge.list(
limit: 20,
offset: 0,
order: "reverse_chronological"
)

charges.data
|> Enum.filter(&(&1.paid))
|> Enum.each(fn charge ->
IO.puts("#{charge.id}: #{charge.amount} #{charge.currency}")
end)

# List charges with date filters
week_ago = DateTime.utc_now() |> DateTime.add(-7, :day) |> DateTime.to_date()
today = Date.utc_today()

{:ok, recent_charges} = Omise.Charge.list(
from: week_ago,
to: today
)

Creating a Customerโ€‹

{:ok, customer} = Omise.Customer.create(
email: "customer@example.com",
description: "John Doe",
metadata: %{
user_id: "12345",
account_type: "premium"
}
)

IO.puts("Customer created: #{customer.id}")

Saving a Card to a Customerโ€‹

# Update customer with a card token
{:ok, customer} = Omise.Customer.update(
"cust_test_123",
card: "tokn_test_456"
)

IO.puts("Card saved: #{customer.default_card}")

# Or create customer with card in one step
{:ok, customer} = Omise.Customer.create(
email: "customer@example.com",
description: "John Doe",
card: "tokn_test_123"
)

Listing Customer Cardsโ€‹

{:ok, customer} = Omise.Customer.retrieve("cust_test_123")

customer.cards.data
|> Enum.each(fn card ->
IO.puts("#{card.brand} ending in #{card.last_digits}")
IO.puts("Expires: #{card.expiration_month}/#{card.expiration_year}")
end)

Creating a Refundโ€‹

# Full refund
{:ok, refund} = Omise.Refund.create(
"chrg_test_123",
%{}
)

# Partial refund
{:ok, refund} = Omise.Refund.create(
"chrg_test_123",
%{
amount: 25_000, # 250.00 THB
metadata: %{
reason: "customer_request",
ticket_id: "TICKET-123"
}
}
)

IO.puts("Refund #{refund.id}: #{refund.amount} #{refund.currency}")

Creating a Transferโ€‹

{:ok, transfer} = Omise.Transfer.create(
amount: 500_000, # 5,000.00 THB
recipient: "recp_test_123",
metadata: %{
payout_id: "PAYOUT-456"
}
)

IO.puts("Transfer #{transfer.id}: #{transfer.amount}")

Alternative Payment Methodsโ€‹

Creating a Sourceโ€‹

# Prompt Pay QR
{:ok, source} = Omise.Source.create(
type: "promptpay",
amount: 100_000,
currency: "THB"
)

IO.puts("QR Code URL: #{source.scannable_code.image.download_uri}")

# Create charge with source
{:ok, charge} = Omise.Charge.create(
amount: 100_000,
currency: "THB",
source: source.id,
return_uri: "https://example.com/payment/callback"
)

Internet Bankingโ€‹

{:ok, source} = Omise.Source.create(
type: "internet_banking_scb",
amount: 100_000,
currency: "THB"
)

{:ok, charge} = Omise.Charge.create(
amount: 100_000,
currency: "THB",
source: source.id,
return_uri: "https://example.com/payment/callback"
)

# Redirect customer to charge.authorize_uri

Mobile Bankingโ€‹

{:ok, source} = Omise.Source.create(
type: "mobile_banking_scb",
amount: 100_000,
currency: "THB"
)

{:ok, charge} = Omise.Charge.create(
amount: 100_000,
currency: "THB",
source: source.id,
return_uri: "https://example.com/payment/callback"
)

Installmentsโ€‹

{:ok, source} = Omise.Source.create(
type: "installment_kbank",
amount: 100_000,
currency: "THB",
installment_term: 6 # 6 months
)

{:ok, charge} = Omise.Charge.create(
amount: 100_000,
currency: "THB",
source: source.id,
return_uri: "https://example.com/payment/callback"
)

Error Handlingโ€‹

defmodule PaymentService do
def create_charge_with_error_handling(params) do
case Omise.Charge.create(params) do
{:ok, charge} ->
{:ok, charge}

{:error, %{code: "authentication_failure"}} ->
{:error, "Invalid API key"}

{:error, %{code: "invalid_card"}} ->
{:error, "Card was declined"}

{:error, %{code: "insufficient_fund"}} ->
{:error, "Insufficient funds"}

{:error, error} ->
{:error, "Payment failed: #{inspect(error)}"}
end
end
end

Custom Error Handlerโ€‹

defmodule PaymentErrorHandler do
@error_messages %{
"insufficient_fund" => "Insufficient funds on card",
"stolen_or_lost_card" => "Card reported as stolen or lost",
"invalid_security_code" => "Invalid CVV code",
"payment_cancelled" => "Payment was cancelled"
}

def get_error_message({:error, %{code: code}}), do: Map.get(@error_messages, code, "Unknown error")
def get_error_message({:error, error}), do: "Error: #{inspect(error)}"
def get_error_message(_), do: "Unknown error"
end

Phoenix Integrationโ€‹

Controller Exampleโ€‹

defmodule MyAppWeb.PaymentController do
use MyAppWeb, :controller

alias MyApp.Payments
alias MyApp.Orders

def create(conn, %{"order_id" => order_id, "omise_token" => token}) do
with {:ok, order} <- Orders.get_order(order_id),
{:ok, charge} <- create_charge(order, token),
{:ok, payment} <- Payments.save_payment(charge, order) do

handle_charge_result(conn, charge, order)
else
{:error, :not_found} ->
conn
|> put_flash(:error, "Order not found")
|> redirect(to: Routes.order_path(conn, :index))

{:error, reason} ->
conn
|> put_flash(:error, "Payment failed: #{reason}")
|> redirect(to: Routes.payment_path(conn, :new, order_id))
end
end

defp create_charge(order, token) do
Omise.Charge.create(
amount: round(order.total * 100),
currency: "THB",
card: token,
description: "Order ##{order.id}",
metadata: %{
order_id: order.id,
customer_email: order.email
},
return_uri: Routes.payment_url(MyAppWeb.Endpoint, :callback)
)
end

defp handle_charge_result(conn, %{paid: true} = charge, order) do
Orders.mark_paid(order)

conn
|> put_flash(:info, "Payment successful!")
|> redirect(to: Routes.order_path(conn, :show, order))
end

defp handle_charge_result(conn, %{authorize_uri: uri} = _charge, _order) when not is_nil(uri) do
redirect(conn, external: uri)
end

defp handle_charge_result(conn, %{failure_message: message}, order) do
conn
|> put_flash(:error, message)
|> redirect(to: Routes.payment_path(conn, :new, order))
end

def callback(conn, %{"id" => charge_id}) do
with {:ok, charge} <- Omise.Charge.retrieve(charge_id),
{:ok, payment} <- Payments.get_by_charge_id(charge_id),
{:ok, _payment} <- Payments.update_status(payment, charge) do

if charge.paid do
conn
|> put_flash(:info, "Payment successful!")
|> redirect(to: Routes.order_path(conn, :show, payment.order_id))
else
conn
|> put_flash(:error, charge.failure_message)
|> redirect(to: Routes.payment_path(conn, :new, payment.order_id))
end
else
{:error, _reason} ->
conn
|> put_flash(:error, "Payment verification failed")
|> redirect(to: Routes.page_path(conn, :index))
end
end
end

Context Moduleโ€‹

defmodule MyApp.Payments do
import Ecto.Query
alias MyApp.Repo
alias MyApp.Payments.Payment

def save_payment(charge, order) do
%Payment{}
|> Payment.changeset(%{
order_id: order.id,
charge_id: charge.id,
amount: Decimal.div(charge.amount, 100),
currency: charge.currency,
status: charge.status,
paid: charge.paid
})
|> Repo.insert()
end

def get_by_charge_id(charge_id) do
case Repo.get_by(Payment, charge_id: charge_id) do
nil -> {:error, :not_found}
payment -> {:ok, payment}
end
end

def update_status(payment, charge) do
payment
|> Payment.changeset(%{
status: charge.status,
paid: charge.paid,
failure_code: charge.failure_code,
failure_message: charge.failure_message
})
|> Repo.update()
end

def charge_customer(customer_id, amount) do
Omise.Charge.create(
amount: round(amount * 100),
currency: "THB",
customer: customer_id
)
end

def refund_charge(charge_id, amount \\ nil) do
params = if amount, do: %{amount: round(amount * 100)}, else: %{}
Omise.Refund.create(charge_id, params)
end
end

Schemaโ€‹

defmodule MyApp.Payments.Payment do
use Ecto.Schema
import Ecto.Changeset

schema "payments" do
field :order_id, :id
field :charge_id, :string
field :amount, :decimal
field :currency, :string, default: "THB"
field :status, :string
field :paid, :boolean, default: false
field :failure_code, :string
field :failure_message, :string
field :refund_id, :string
field :refund_amount, :decimal

timestamps()
end

def changeset(payment, attrs) do
payment
|> cast(attrs, [
:order_id, :charge_id, :amount, :currency, :status,
:paid, :failure_code, :failure_message, :refund_id, :refund_amount
])
|> validate_required([:order_id, :amount, :currency, :status])
|> validate_number(:amount, greater_than: 0)
|> unique_constraint(:charge_id)
end
end

GenServer for Background Processingโ€‹

Payment Processorโ€‹

defmodule MyApp.PaymentProcessor do
use GenServer
require Logger

def start_link(opts) do
GenServer.start_link(__MODULE__, opts, name: __MODULE__)
end

def process_charge(token, amount, metadata) do
GenServer.call(__MODULE__, {:process_charge, token, amount, metadata})
end

@impl true
def init(_opts) do
{:ok, %{}}
end

@impl true
def handle_call({:process_charge, token, amount, metadata}, _from, state) do
result = case Omise.Charge.create(
amount: amount,
currency: "THB",
card: token,
metadata: metadata
) do
{:ok, %{paid: true} = charge} ->
Logger.info("Charge successful: #{charge.id}")
{:ok, charge}

{:ok, %{paid: false, failure_message: message} = charge} ->
Logger.error("Charge failed: #{message}")
{:error, message}

{:error, error} ->
Logger.error("Charge error: #{inspect(error)}")
{:error, error}
end

{:reply, result, state}
end
end

Subscription Managerโ€‹

defmodule MyApp.SubscriptionManager do
use GenServer
require Logger

alias MyApp.Repo
alias MyApp.Subscriptions.Subscription

def start_link(opts) do
GenServer.start_link(__MODULE__, opts, name: __MODULE__)
end

@impl true
def init(_opts) do
schedule_work()
{:ok, %{}}
end

@impl true
def handle_info(:charge_subscriptions, state) do
charge_all_subscriptions()
schedule_work()
{:noreply, state}
end

defp schedule_work do
# Schedule for next day at midnight
next_run = calculate_next_midnight()
Process.send_after(self(), :charge_subscriptions, next_run)
end

defp charge_all_subscriptions do
Subscription
|> where([s], s.status == "active")
|> Repo.all()
|> Enum.each(&charge_subscription/1)
end

defp charge_subscription(subscription) do
case Omise.Charge.create(
amount: subscription.plan_amount,
currency: "THB",
customer: subscription.customer_id,
description: "Subscription #{Date.utc_today()}"
) do
{:ok, %{paid: true}} ->
subscription
|> Ecto.Changeset.change(last_charge_date: DateTime.utc_now())
|> Repo.update()

Logger.info("Charged subscription #{subscription.id}")

{:error, error} ->
Logger.error("Failed to charge subscription #{subscription.id}: #{inspect(error)}")
end
end

defp calculate_next_midnight do
now = DateTime.utc_now()
tomorrow = DateTime.add(now, 1, :day)
midnight = %{tomorrow | hour: 0, minute: 0, second: 0, microsecond: {0, 0}}
DateTime.diff(midnight, now, :millisecond)
end
end

Task for Async Operationsโ€‹

defmodule MyApp.AsyncPayment do
def process_charges_async(charge_params_list) do
charge_params_list
|> Enum.map(fn params ->
Task.async(fn -> create_charge(params) end)
end)
|> Enum.map(&Task.await/1)
end

defp create_charge(params) do
case Omise.Charge.create(params) do
{:ok, charge} -> {:ok, charge}
{:error, error} -> {:error, error}
end
end
end

# Usage
charge_params = [
%{amount: 100_000, currency: "THB", card: "tokn_test_1"},
%{amount: 200_000, currency: "THB", card: "tokn_test_2"}
]

results = MyApp.AsyncPayment.process_charges_async(charge_params)

Best Practicesโ€‹

1. Use Pattern Matchingโ€‹

def process_payment(token, amount) do
case Omise.Charge.create(amount: amount, currency: "THB", card: token) do
{:ok, %{paid: true, id: charge_id}} ->
# Handle successful payment
{:ok, charge_id}

{:ok, %{authorize_uri: uri}} when not is_nil(uri) ->
# Handle 3D Secure redirect
{:redirect, uri}

{:ok, %{failure_message: message}} ->
# Handle failed payment
{:error, message}

{:error, %{code: code, message: message}} ->
# Handle API error
{:error, "#{code}: #{message}"}
end
end

2. Use Pipes for Data Transformationโ€‹

def list_paid_charges do
{:ok, charges} = Omise.Charge.list(limit: 100)

charges.data
|> Enum.filter(&(&1.paid))
|> Enum.map(&extract_charge_info/1)
|> Enum.sort_by(& &1.created, :desc)
end

defp extract_charge_info(charge) do
%{
id: charge.id,
amount: charge.amount / 100,
currency: charge.currency,
created: charge.created
}
end

3. Use Structs for Type Safetyโ€‹

defmodule MyApp.Money do
defstruct amount: 0, currency: "THB"

def new(amount, currency \\ "THB") do
%__MODULE__{amount: round(amount * 100), currency: currency}
end

def to_baht(%__MODULE__{amount: amount}), do: amount / 100
end

# Usage
money = MyApp.Money.new(1000.00)
{:ok, charge} = Omise.Charge.create(
amount: money.amount,
currency: money.currency,
card: token
)

4. Implement Idempotencyโ€‹

def create_idempotent_charge(params, order_id) do
idempotency_key = "order-#{order_id}-#{:os.system_time(:millisecond)}"

Omise.Charge.create(
params,
headers: [{"Idempotency-Key", idempotency_key}]
)
end

5. Use Supervisors for Fault Toleranceโ€‹

defmodule MyApp.Application do
use Application

def start(_type, _args) do
children = [
MyApp.Repo,
MyAppWeb.Endpoint,
MyApp.PaymentProcessor,
MyApp.SubscriptionManager
]

opts = [strategy: :one_for_one, name: MyApp.Supervisor]
Supervisor.start_link(children, opts)
end
end

6. Use Telemetry for Monitoringโ€‹

defmodule MyApp.PaymentTelemetry do
def handle_event([:omise, :charge, :create], measurements, metadata, _config) do
Logger.info("Charge created",
charge_id: metadata.charge_id,
amount: metadata.amount,
duration: measurements.duration
)
end
end

# Attach handler
:telemetry.attach(
"payment-handler",
[:omise, :charge, :create],
&MyApp.PaymentTelemetry.handle_event/4,
nil
)

Testingโ€‹

ExUnit Testsโ€‹

defmodule MyApp.PaymentsTest do
use MyApp.DataCase

alias MyApp.Payments

import Mox

setup :verify_on_exit!

describe "create_charge/2" do
test "creates a successful charge" do
expect(OmiseMock, :create_charge, fn _params ->
{:ok, %{
id: "chrg_test_123",
amount: 100_000,
currency: "THB",
paid: true,
status: "successful"
}}
end)

assert {:ok, charge} = Payments.create_charge("tokn_test_123", 1000.00)
assert charge.id == "chrg_test_123"
assert charge.paid == true
end

test "handles charge failure" do
expect(OmiseMock, :create_charge, fn _params ->
{:error, %{code: "insufficient_fund", message: "Insufficient funds"}}
end)

assert {:error, error} = Payments.create_charge("tokn_test_123", 1000.00)
assert error.code == "insufficient_fund"
end
end
end

Integration Testsโ€‹

defmodule MyAppWeb.PaymentControllerTest do
use MyAppWeb.ConnCase

alias MyApp.Orders

setup do
order = Orders.create_order!(%{total: 1000.00, email: "test@example.com"})
{:ok, order: order}
end

describe "POST /payment/:order_id" do
@tag :integration
test "creates a payment successfully", %{conn: conn, order: order} do
# Use test token
token = "tokn_test_5086xl7ddjbases4sq3i"

conn = post(conn, Routes.payment_path(conn, :create, order.id), %{
"omise_token" => token
})

assert redirected_to(conn) == Routes.order_path(conn, :show, order)
assert get_flash(conn, :info) == "Payment successful!"
end
end
end

Mock for Testingโ€‹

# test/support/mocks.ex
Mox.defmock(OmiseMock, for: MyApp.PaymentBehaviour)

# lib/my_app/payment_behaviour.ex
defmodule MyApp.PaymentBehaviour do
@callback create_charge(map()) :: {:ok, map()} | {:error, map()}
@callback retrieve_charge(String.t()) :: {:ok, map()} | {:error, map()}
end

# Use in application
defmodule MyApp.Payments do
@payment_client Application.compile_env(:my_app, :payment_client, Omise)

def create_charge(params) do
@payment_client.Charge.create(params)
end
end

# In test config
config :my_app, payment_client: OmiseMock

Troubleshootingโ€‹

Connection Timeoutโ€‹

# Configure HTTP client timeout
config :omise,
http_options: [timeout: 60_000, recv_timeout: 60_000]

Debug Loggingโ€‹

# Enable debug logging
config :logger, level: :debug

config :omise, debug: true

Webhook Signature Verificationโ€‹

defmodule MyAppWeb.WebhookController do
use MyAppWeb, :controller

def omise(conn, _params) do
with {:ok, payload} <- read_body(conn),
{:ok, signature} <- get_signature(conn),
true <- verify_signature(payload, signature) do

payload
|> Jason.decode!()
|> handle_webhook()

json(conn, %{status: "ok"})
else
false ->
conn
|> put_status(:unauthorized)
|> json(%{error: "Invalid signature"})

{:error, _reason} ->
conn
|> put_status(:bad_request)
|> json(%{error: "Invalid request"})
end
end

defp get_signature(conn) do
case get_req_header(conn, "omise-signature") do
[signature] -> {:ok, signature}
_ -> {:error, :no_signature}
end
end

defp verify_signature(payload, signature) do
secret = Application.get_env(:omise, :webhook_secret)
expected = :crypto.mac(:hmac, :sha256, secret, payload) |> Base.encode16(case: :lower)
Plug.Crypto.secure_compare(signature, expected)
end

defp handle_webhook(%{"key" => "charge.complete", "data" => data}) do
# Handle charge completion
end

defp handle_webhook(%{"key" => "refund.create", "data" => data}) do
# Handle refund creation
end

defp handle_webhook(_), do: :ok
end

FAQโ€‹

How do I handle webhooks in Phoenix?โ€‹

defmodule MyAppWeb.WebhookController do
use MyAppWeb, :controller

def omise(conn, _params) do
{:ok, body, conn} = read_body(conn)
event = Jason.decode!(body)

case event["key"] do
"charge.complete" ->
handle_charge_complete(event["data"])
"refund.create" ->
handle_refund_create(event["data"])
end

json(conn, %{status: "ok"})
end

defp handle_charge_complete(%{"id" => charge_id}) do
{:ok, charge} = Omise.Charge.retrieve(charge_id)
MyApp.Payments.update_charge_status(charge)
end
end

How do I test without real charges?โ€‹

# Use test API keys in config/test.exs
config :omise,
public_key: "pkey_test_123456789",
secret_key: "skey_test_123456789"

# Use test tokens
{:ok, charge} = Omise.Charge.create(
amount: 100_000,
currency: "THB",
card: "tokn_test_5086xl7ddjbases4sq3i"
)

# Verify test mode
assert charge.livemode == false

How do I handle partial refunds?โ€‹

def refund_charge(charge_id, refund_amount \\ nil) do
with {:ok, charge} <- Omise.Charge.retrieve(charge_id) do
refundable = charge.amount - charge.refunded

params = case refund_amount do
nil -> %{}
amount when amount <= refundable -> %{amount: round(amount * 100)}
_ -> {:error, :amount_exceeds_refundable}
end

case params do
{:error, reason} -> {:error, reason}
_ -> Omise.Refund.create(charge_id, params)
end
end
end

How do I save multiple cards for a customer?โ€‹

def add_card_to_customer(customer_id, token) do
Omise.Customer.update(customer_id, card: token)
end

def list_customer_cards(customer_id) do
with {:ok, customer} <- Omise.Customer.retrieve(customer_id) do
{:ok, customer.cards.data}
end
end

def charge_specific_card(customer_id, card_id, amount) do
Omise.Charge.create(
amount: round(amount * 100),
currency: "THB",
customer: customer_id,
card: card_id
)
end

How do I implement subscription billing?โ€‹

defmodule MyApp.SubscriptionBilling do
def charge_monthly(customer_id, plan_amount) do
Omise.Charge.create(
amount: plan_amount,
currency: "THB",
customer: customer_id,
description: "Subscription #{Date.utc_today()}"
)
end
end

# Use with Quantum for scheduling
config :my_app, MyApp.Scheduler,
jobs: [
{"0 0 1 * *", {MyApp.SubscriptionBilling, :charge_all, []}}
]

How do I implement retry logic?โ€‹

def create_charge_with_retry(params, retries \\ 3) do
case Omise.Charge.create(params) do
{:ok, charge} ->
{:ok, charge}

{:error, _error} when retries > 0 ->
:timer.sleep(:math.pow(2, 3 - retries) * 1000 |> round())
create_charge_with_retry(params, retries - 1)

{:error, error} ->
{:error, error}
end
end

Next Stepsโ€‹

Supportโ€‹

If you encounter issues with the Elixir library:

  1. Check the GitHub Issues
  2. Review the API documentation
  3. Contact support@omise.co with:
    • Elixir version
    • omise-elixir library version
    • Error message and stack trace
    • Steps to reproduce