Skip to main content

README.md

# Conekta Elixir

Elixir wrapper for the [Conekta API](https://api.conekta.io).

[HexDocs documentation](https://hexdocs.pm/conekta/api-reference.html)

## Installation

Add `conekta` to your `mix.exs` dependencies:

```elixir
defp deps do
  [
    {:conekta, "~> 1.1"}
  ]
end
```

Then run:

```bash
mix deps.get
```

## Configuration

Add your API keys in `config/config.exs`:

```elixir
config :conekta,
  publickey: "YOUR_PUBLIC_KEY",
  privatekey: "YOUR_PRIVATE_KEY",
  locale: "es",
  apiversion: "2.0.0"
```

You can also set configuration per-process for multi-tenant use:

```elixir
Conekta.Wrapper.put_config(%{
  privatekey: "key_for_this_tenant",
  locale: "es",
  apiversion: "2.0.0"
})
```

## Usage

### Customers

```elixir
# List all customers
{:ok, customers} = Conekta.Customers.customers()

# Create a customer
new_customer = %Conekta.Customer{
  name: "Jane Doe",
  email: "jane@example.com",
  corporate: true,
  payment_sources: [%{
    token_id: "tok_test_visa_4242",
    type: "card"
  }]
}
{:ok, customer} = Conekta.Customers.create(new_customer)

# Find, update, delete
{:ok, customer} = Conekta.Customers.find("cus_abc123")
{:ok, updated} = Conekta.Customers.update("cus_abc123", %Conekta.Customer{name: "New Name"})
{:ok, deleted} = Conekta.Customers.delete("cus_abc123")
```

#### Payment Sources

```elixir
{:ok, sources} = Conekta.Customers.payment_sources("cus_abc123")
{:ok, source} = Conekta.Customers.create_payment_source("cus_abc123", %{
  token_id: "tok_test_visa_4242",
  type: "card"
})
{:ok, deleted} = Conekta.Customers.delete_payment_source("cus_abc123", "src_xyz")
```

#### Shipping Contacts

```elixir
{:ok, contacts} = Conekta.Customers.shipping_contacts("cus_abc123")
{:ok, contact} = Conekta.Customers.create_shipping_contact("cus_abc123", %{
  phone: "1234567890",
  address: %{street1: "123 Main St", postal_code: "00000", country: "MX"}
})
{:ok, updated} = Conekta.Customers.update_shipping_contact("cus_abc123", "ship_xyz", %{
  phone: "0987654321"
})
{:ok, deleted} = Conekta.Customers.delete_shipping_contact("cus_abc123", "ship_xyz")
```

### Orders

```elixir
# List all orders
{:ok, orders} = Conekta.Orders.orders()

# Create an order
new_order = %Conekta.Order{
  currency: "MXN",
  customer_info: %{customer_id: "cus_abc123"},
  line_items: [%{name: "Product 1", unit_price: 35_000, quantity: 1}],
  charges: [%{payment_method: %{type: "default"}}]
}
{:ok, order} = Conekta.Orders.create(new_order)

# Find, update
{:ok, order} = Conekta.Orders.find("ord_abc123")
{:ok, updated} = Conekta.Orders.update("ord_abc123", %Conekta.Order{currency: "USD"})

# Charges
{:ok, charges} = Conekta.Orders.charges("ord_abc123")
{:ok, charge} = Conekta.Orders.create_charge("ord_abc123", %{
  payment_method: %{type: "default"}
})

# Refunds
{:ok, refund} = Conekta.Orders.refund("ord_abc123", %{reason: "requested_by_client"})
{:ok, refund} = Conekta.Orders.partial_refund("ord_abc123", %{
  reason: "requested_by_client",
  amount: 10_000
})
```

### Plans

```elixir
# Create a plan
plan = %Conekta.Plan{
  name: "Monthly Plan",
  amount: 5000,
  currency: "MXN",
  interval: "month",
  frequency: 1
}
{:ok, created} = Conekta.Plans.create(plan)

# List, find, update, delete
{:ok, plans} = Conekta.Plans.plans()
{:ok, plan} = Conekta.Plans.find("plan_abc123")
{:ok, updated} = Conekta.Plans.update("plan_abc123", %Conekta.Plan{name: "Updated Plan"})
{:ok, deleted} = Conekta.Plans.delete("plan_abc123")
```

### Subscriptions

Manage the full subscription lifecycle on a customer:

```elixir
# Create a subscription
{:ok, sub} = Conekta.Subscriptions.create("cus_abc123", %Conekta.SubscriptionRequest{
  plan_id: "plan_abc123"
})

# Get, update
{:ok, sub} = Conekta.Subscriptions.get("cus_abc123")
{:ok, sub} = Conekta.Subscriptions.update("cus_abc123", %Conekta.SubscriptionRequest{
  plan_id: "plan_new"
})

# Pause, resume, cancel
{:ok, sub} = Conekta.Subscriptions.pause("cus_abc123")
{:ok, sub} = Conekta.Subscriptions.resume("cus_abc123")
{:ok, sub} = Conekta.Subscriptions.cancel("cus_abc123")
```

### Payment Links

Generate payment URLs to send to customers:

```elixir
# Create a payment link
checkout = %Conekta.Checkout{
  name: "Product Payment",
  type: "PaymentLink",
  allowed_payment_methods: ["card", "cash"],
  recurrent: false,
  order_template: %Conekta.CheckoutOrderTemplate{
    currency: "MXN",
    line_items: [%{name: "T-Shirt", unit_price: 25_000, quantity: 1}]
  }
}
{:ok, link} = Conekta.PaymentLinks.create(checkout)
IO.puts(link.url) # => "https://pay.conekta.com/checkout/..."

# List, find, cancel
{:ok, links} = Conekta.PaymentLinks.list()
{:ok, link} = Conekta.PaymentLinks.find("checkout_abc123")
{:ok, canceled} = Conekta.PaymentLinks.cancel("checkout_abc123")

# Send via email or SMS
{:ok, link} = Conekta.PaymentLinks.send_email("checkout_abc123", "customer@example.com")
{:ok, link} = Conekta.PaymentLinks.send_sms("checkout_abc123", "+521234567890")
```

### Charges

List and update charges across all orders:

```elixir
{:ok, charges} = Conekta.Charges.list()
{:ok, charge} = Conekta.Charges.find("chr_abc123")
{:ok, updated} = Conekta.Charges.update("chr_abc123", %Conekta.ChargeUpdateRequest{
  reference_id: "my_ref_123"
})
```

### Tokens

Tokenize card data for secure payment processing:

```elixir
token = %Conekta.Token{
  card: %Conekta.TokenCard{
    number: "4242424242424242",
    name: "John Doe",
    exp_month: "12",
    exp_year: "25",
    cvc: "123"
  }
}
{:ok, result} = Conekta.Tokens.create(token)
IO.puts(result.id) # => "tok_..."
```

### Webhooks

#### Managing Webhook Endpoints

Register, update, and test your webhook URLs:

```elixir
# Register a webhook endpoint
{:ok, wh} = Conekta.Webhooks.create(%Conekta.WebhookRequest{
  url: "https://myapp.com/api/webhooks/conekta",
  subscribed_events: ["charge.paid", "order.created"]
})

# List, find, update, delete
{:ok, webhooks} = Conekta.Webhooks.list()
{:ok, wh} = Conekta.Webhooks.find("wh_abc123")
{:ok, wh} = Conekta.Webhooks.update("wh_abc123", %Conekta.WebhookUpdateRequest{
  url: "https://myapp.com/api/v2/webhooks"
})
{:ok, deleted} = Conekta.Webhooks.delete("wh_abc123")

# Send a test ping
{:ok, wh} = Conekta.Webhooks.test("wh_abc123")
```

#### Parsing Incoming Webhooks

Handle webhook payloads in your controller:

```elixir
case Conekta.WebHook.received(params) do
  {:charge_created, charge} -> # handle new charge
  {:charge_paid, charge} -> # handle paid charge
  {:plan_created, plan} -> # handle new plan
  {:customer_created, customer} -> # handle new customer
  {:subscription_created, sub} -> # handle new subscription
  {:subscription_paid, sub} -> # handle paid subscription
  {:subscription_canceled, sub} -> # handle canceled subscription
  {:chargeback_created, cb} -> # handle new chargeback
  {:chargeback_lost, cb} -> # handle lost chargeback
  {:error, message} -> # handle unknown event
end

# Include webhook logs
{:charge_paid, charge, logs} = Conekta.WebHook.received(params, :logs)
```

### Events

Retrieve and resend webhook events:

```elixir
{:ok, events} = Conekta.Events.list()
{:ok, event} = Conekta.Events.find("evt_abc123")
{:ok, resent} = Conekta.Events.resend("evt_abc123", "webhook_log_id")
```

### Balances

Check your account balance:

```elixir
{:ok, balance} = Conekta.Balances.get()
```

## Testing

Run unit tests:

```bash
mix test
```

Run integration tests against Conekta's sandbox (requires `CONEKTA_PRIVATE_KEY`):

```bash
export CONEKTA_PRIVATE_KEY=your_sandbox_key
mix test test/integration --include integration
```

## Contributing

1. Fork the repository
2. Create your feature branch (`git checkout -b feature/my-feature`)
3. Commit your changes (`git commit -am 'Add my feature'`)
4. Push to the branch (`git push origin feature/my-feature`)
5. Open a Pull Request

## License

[MIT](LICENSE)