Txenka
API Reference

Documentation

Everything you need to integrate with the Txenka API — payments, refunds, customers, products, payment links, webhooks, and full account management.

Introduction Authentication Create a payment Confirm payment Manage Payment Intents Transactions Refunds Customers Products Invoices Payment links Store profile API Keys Catalog Stats Request logs Payment methods Webhooks Errors Help

Introduction

The Txenka API is built around payment_intents — every payment you create and confirm. All requests and responses use JSON, and the base URL is https://api.txenka.com/api/v1.

Authentication

Every authenticated call uses your API key in the Authorization header. Find your key under Developers → API Keys in the dashboard — use txk_test_… to test without processing real money, and txk_live_… in production. Each key picks its own permissions (scopes) — give every integration only the access it needs.

HTTP Header
Authorization: Bearer txk_test_8f2a3c9d1e...

Scopes

Each API Key picks its own scopes at creation — restrict every integration to only what it needs. A publishable key may only carry payments:read, payments:confirm and transactions:read — never payments:write, which would create Payment Intents with an arbitrary amount.

payments:read Read Payment Intents
payments:write Create Payment Intents
payments:confirm Confirm an already-created Payment Intent (safe on a publishable key)
payments:cancel Cancel payments
transactions:read Read transactions
refunds:read Read refunds
refunds:write Create refunds
webhooks:read Read webhooks
webhooks:write Manage webhooks
customers:read Read customers
customers:write Manage customers
products:read Read products
products:write Manage products
invoices:read Read invoices
invoices:write Manage invoices
payment_links:read Read payment links
payment_links:write Manage payment links
bank_accounts:read Read receiving bank accounts
bank_accounts:write Manage receiving bank accounts
payout_accounts:read Read payout accounts
payout_accounts:write Manage payout accounts
withdrawals:read Read withdrawals
withdrawals:write Request withdrawals
billing:read Read billing/subscription
billing:write Manage billing/subscription
devices:read Read paired devices
devices:write Manage paired devices
api_keys:read List API Keys
api_keys:write Create, edit and revoke API Keys

Create a payment

A payment_intent represents a charge. Amounts are always in cents (2450 = 24.50 MZN). amount, customer_email and customer_name are required; payment_method is optional — if omitted, the customer picks a method on the checkout page itself.

curl -X POST https://api.txenka.com/api/v1/payment-intents \
  -H "Authorization: Bearer txk_test_8f2a3c9d1e..." \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 2450,
    "currency": "MZN",
    "payment_method": "mpesa",
    "customer_phone": "258840000000",
    "customer_email": "cliente@exemplo.com",
    "customer_name": "Ana Machava",
    "description": "Pedido #1042",
    "merchant_reference": "PEDIDO-1042"
  }'

The response already includes a ready-to-use checkout_url — redirect the customer there and Txenka handles confirmation for you, no need to implement the next step. client_secret only authorizes reading/confirming this specific payment, never your other intents — safe to share over any channel (WhatsApp, SMS, email).

Response
{
  "object": "payment_intent",
  "id": "01HX4K9GVZ3QY8N7T2WPJD5R6E",
  "amount": 2450,
  "amount_decimal": "24.50",
  "currency": "MZN",
  "status": "requires_confirmation",
  "payment_method": "mpesa",
  "description": "Pedido #1042",
  "merchant_reference": "PEDIDO-1042",
  "merchant": { "name": "A Tua Loja", "logo_url": null },
  "available_payment_methods": [
    { "key": "mpesa", "name": "M-Pesa", "icon": "...", "type": "wallet", "needs_phone": true, "customer_instructions": "..." }
  ],
  "checkout_url": "https://pay.txenka.com/checkout/01HX4K9GVZ3QY8N7T2WPJD5R6E_secret_a1b2c3...",
  "client_secret": "01HX4K9GVZ3QY8N7T2WPJD5R6E_secret_a1b2c3...",
  "customer": { "email": "cliente@exemplo.com", "phone": "+258840000000", "name": "Ana Machava" },
  "success_url": null,
  "cancel_url": null,
  "failure_code": null,
  "failure_message": null,
  "metadata": {},
  "latest_transaction": null,
  "created_at": "2026-07-30T10:00:00+00:00",
  "updated_at": "2026-07-30T10:00:00+00:00",
  "cancelled_at": null,
  "expires_at": "2026-07-30T11:00:00+00:00"
}

Confirm the payment

Confirming triggers the request with the chosen method — for example, an STK push request on the customer's phone for M-Pesa/e-Mola.

curl -X POST https://api.txenka.com/api/v1/payment-intents/01HX4K9GVZ3QY8N7T2WPJD5R6E/confirm \
  -H "Authorization: Bearer txk_test_8f2a3c9d1e..."
Response
{
  "object": "payment_intent",
  "id": "01HX4K9GVZ3QY8N7T2WPJD5R6E",
  "status": "processing",
  "payment_method": "mpesa",
  "failure_code": null,
  "failure_message": null,
  "latest_transaction": {
    "object": "transaction",
    "id": "01HABCXYZ...",
    "provider_reference": "ws_CO_2607261...",
    "status": "pending"
  }
}

The returned status can be succeeded (immediate), processing (awaiting async confirmation — the final result arrives by webhook) or failed (see failure_code/failure_message).

A failed status isn't final — call POST /payment-intents/{id}/reset-method to clear the method and confirm again with a different one, without creating a new intent. This differs from cancelling (which ends the intent for good).

Manage Payment Intents

Beyond creating and confirming, list the intent history, cancel one for good, or let the customer pick a different method without losing the intent.

List

Filter by status, payment_method, from/to (dates), and paginate with limit.

curl "https://api.txenka.com/api/v1/payment-intents?status=succeeded&limit=20" \
  -H "Authorization: Bearer txk_test_8f2a3c9d1e..."

Retrieve one

curl https://api.txenka.com/api/v1/payment-intents/01HX4K9GVZ3QY8N7T2WPJD5R6E \
  -H "Authorization: Bearer txk_test_8f2a3c9d1e..."

Cancel

Ends the intent for good — same as Stripe's PaymentIntent.cancel. Once cancelled (or already succeeded), there's no going back — use reset-method below if you only need the customer to try a different method.

curl -X POST https://api.txenka.com/api/v1/payment-intents/01HX4K9GVZ3QY8N7T2WPJD5R6E/cancel \
  -H "Authorization: Bearer txk_test_8f2a3c9d1e..."

Reset the payment method

Different from cancel: clears only the payment_method of the current attempt and returns the intent to requires_payment_method, without ending the intent or its checkout_url. Useful when a synchronous attempt (mpesa/card) was declined, or a manual/async attempt (bank transfer, SMS relay) was left pending and the customer gave up — lets them pick another method on the same link instead of you creating a new Payment Intent. Allowed from any non-terminal state, including failed (a decline is meant to be retried); blocked only from succeeded/cancelled.

curl -X POST https://api.txenka.com/api/v1/payment-intents/01HX4K9GVZ3QY8N7T2WPJD5R6E/reset-method \
  -H "Authorization: Bearer txk_test_8f2a3c9d1e..."

Transactions

Every charge attempt against a Payment Intent produces a transaction — one intent can have several, if the customer fails and retries.

List

curl "https://api.txenka.com/api/v1/transactions?status=succeeded&payment_method=mpesa" \
  -H "Authorization: Bearer txk_test_8f2a3c9d1e..."

Retrieve one

curl https://api.txenka.com/api/v1/transactions/txn_01hx4k9… \
  -H "Authorization: Bearer txk_test_8f2a3c9d1e..."
Response
{
  "object": "transaction",
  "id": "txn_01hx4k9…",
  "payment_intent_id": "01HX4K9GVZ3QY8N7T2WPJD5R6E",
  "amount": 2450,
  "currency": "MZN",
  "status": "succeeded",
  "payment_method": "mpesa",
  "provider_reference": "MP240730.1234.A56789",
  "amount_refunded": 0,
  "is_refundable": true
}

Refunds

Fully or partially refund a successful transaction. Methods with automatic reversal change state right away; manual ones (bank transfer, SMS relay) stay pending until you're notified by webhook.

List

curl https://api.txenka.com/api/v1/refunds \
  -H "Authorization: Bearer txk_test_8f2a3c9d1e..."

Create (on a transaction)

amount is optional — omitted, it refunds whatever hasn't been refunded yet. reason accepts duplicate, fraudulent, requested_by_customer or other.

curl -X POST https://api.txenka.com/api/v1/transactions/txn_01hx4k9…/refunds \
  -H "Authorization: Bearer txk_test_8f2a3c9d1e..." \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 1000,
    "reason": "requested_by_customer",
    "notes": "Cliente desistiu da encomenda"
  }'

Retrieve one

curl https://api.txenka.com/api/v1/refunds/re_01hx4k9… \
  -H "Authorization: Bearer txk_test_8f2a3c9d1e..."

Customers

A simple record for your customer — name, email, phone — to reuse on invoices and to search their payment history.

List

curl "https://api.txenka.com/api/v1/customers?search=Ana&limit=25" \
  -H "Authorization: Bearer txk_test_8f2a3c9d1e..."

Create

curl -X POST https://api.txenka.com/api/v1/customers \
  -H "Authorization: Bearer txk_test_8f2a3c9d1e..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Ana Machava",
    "email": "ana@example.com",
    "phone": "258840000000",
    "country": "MZ"
  }'

Retrieve one

curl https://api.txenka.com/api/v1/customers/cus_01hx4k9… \
  -H "Authorization: Bearer txk_test_8f2a3c9d1e..."

Update

curl -X PATCH https://api.txenka.com/api/v1/customers/cus_01hx4k9… \
  -H "Authorization: Bearer txk_test_8f2a3c9d1e..." \
  -H "Content-Type: application/json" \
  -d '{"phone": "258850000000"}'

Delete

curl -X DELETE https://api.txenka.com/api/v1/customers/cus_01hx4k9… \
  -H "Authorization: Bearer txk_test_8f2a3c9d1e..."

Products

A simple catalog to reuse on invoices and payment links. Note: unlike payment_intents, price here is a decimal value in the major unit (899.90 = 899.90 MZN) — the API converts to cents internally.

List

curl "https://api.txenka.com/api/v1/products?status=active&search=camisa" \
  -H "Authorization: Bearer txk_test_8f2a3c9d1e..."

Create

curl -X POST https://api.txenka.com/api/v1/products \
  -H "Authorization: Bearer txk_test_8f2a3c9d1e..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Camisa polo",
    "price": 899.90,
    "currency": "MZN",
    "sku": "POLO-001"
  }'

Retrieve one

curl https://api.txenka.com/api/v1/products/prod_01hx4k9… \
  -H "Authorization: Bearer txk_test_8f2a3c9d1e..."

Update

curl -X PATCH https://api.txenka.com/api/v1/products/prod_01hx4k9… \
  -H "Authorization: Bearer txk_test_8f2a3c9d1e..." \
  -H "Content-Type: application/json" \
  -d '{"price": 949.90, "status": "inactive"}'

Delete

curl -X DELETE https://api.txenka.com/api/v1/products/prod_01hx4k9… \
  -H "Authorization: Bearer txk_test_8f2a3c9d1e..."

Invoices

Aggregates several line_items into a total billed to a customer, with a due date. Same decimal convention as Products for prices/quantities.

List

curl "https://api.txenka.com/api/v1/invoices?status=sent&limit=25" \
  -H "Authorization: Bearer txk_test_8f2a3c9d1e..."

Create

The invoice number (INV-2026-0001) is generated automatically. Totals (subtotal, total) are computed from line_items, not sent by you.

curl -X POST https://api.txenka.com/api/v1/invoices \
  -H "Authorization: Bearer txk_test_8f2a3c9d1e..." \
  -H "Content-Type: application/json" \
  -d '{
    "customer_id": "cus_01hx4k9…",
    "issued_at": "2026-07-30",
    "due_at": "2026-08-13",
    "line_items": [
      {"description": "Camisa polo", "quantity": 2, "unit_price": 899.90}
    ]
  }'

Retrieve one

curl https://api.txenka.com/api/v1/invoices/inv_01hx4k9… \
  -H "Authorization: Bearer txk_test_8f2a3c9d1e..."

Update (status, notes, due date)

curl -X PATCH https://api.txenka.com/api/v1/invoices/inv_01hx4k9… \
  -H "Authorization: Bearer txk_test_8f2a3c9d1e..." \
  -H "Content-Type: application/json" \
  -d '{"status": "paid", "paid_at": "2026-07-30T10:00:00Z"}'

Delete

curl -X DELETE https://api.txenka.com/api/v1/invoices/inv_01hx4k9… \
  -H "Authorization: Bearer txk_test_8f2a3c9d1e..."

Store Profile

Public and contact data for your account, and which payment methods are active and how they're configured.

Retrieve the profile

curl https://api.txenka.com/api/v1/merchants/me \
  -H "Authorization: Bearer txk_test_8f2a3c9d1e..."

Update the profile

curl -X PATCH https://api.txenka.com/api/v1/merchants/me \
  -H "Authorization: Bearer txk_test_8f2a3c9d1e..." \
  -H "Content-Type: application/json" \
  -d '{"support_email": "suporte@minhaloja.co.mz", "website": "https://minhaloja.co.mz"}'

Active methods

enabled_methods may only contain methods already authorized by Txenka for your account (see merchant.payment_methods.authorized in the GET /merchants/me response) — use the request endpoint below to ask for a new one.

curl -X PATCH https://api.txenka.com/api/v1/merchants/me/payment-methods \
  -H "Authorization: Bearer txk_test_8f2a3c9d1e..." \
  -H "Content-Type: application/json" \
  -d '{"enabled_methods": ["mpesa", "emola", "card"]}'

Retrieve a method's config

curl https://api.txenka.com/api/v1/merchants/me/payment-methods/mpesa \
  -H "Authorization: Bearer txk_test_8f2a3c9d1e..."

Configure a method (direct vs custom)

mode: "direct" uses Txenka's official/pooled integration; mode: "custom" uses your own credentials with the operator/bank (stored encrypted). Requires KYC and KYB approved.

curl -X PATCH https://api.txenka.com/api/v1/merchants/me/payment-methods/mpesa \
  -H "Authorization: Bearer txk_test_8f2a3c9d1e..." \
  -H "Content-Type: application/json" \
  -d '{
    "mode": "custom",
    "credentials": {"api_key": "...", "public_key": "..."},
    "enabled": true
  }'

Request authorization for a method

Sends a request to an admin to enable a method not yet authorized for your account (e.g. bank_transfer_atm). Idempotent — re-requesting just reopens an existing rejected/pending request.

curl -X POST https://api.txenka.com/api/v1/merchants/me/payment-methods/bank_transfer_atm/request \
  -H "Authorization: Bearer txk_test_8f2a3c9d1e..."

API Keys

Create and manage your API keys — each with its own type (test/live), scopes, and optionally an IP whitelist and expiration.

List

curl https://api.txenka.com/api/v1/api-keys \
  -H "Authorization: Bearer txk_test_8f2a3c9d1e..."

Create

The full key value is only ever returned in this response — save it now, it can't be retrieved afterward.

curl -X POST https://api.txenka.com/api/v1/api-keys \
  -H "Authorization: Bearer txk_test_8f2a3c9d1e..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Integração e-commerce",
    "type": "test",
    "kind": "secret",
    "scopes": ["payments:read", "payments:write", "payments:confirm"]
  }'

Retrieve one

curl https://api.txenka.com/api/v1/api-keys/17 \
  -H "Authorization: Bearer txk_test_8f2a3c9d1e..."

Update (name, scopes, IP whitelist)

curl -X PATCH https://api.txenka.com/api/v1/api-keys/17 \
  -H "Authorization: Bearer txk_test_8f2a3c9d1e..." \
  -H "Content-Type: application/json" \
  -d '{"scopes": ["payments:read", "transactions:read"]}'

Revoke

curl -X DELETE https://api.txenka.com/api/v1/api-keys/17 \
  -H "Authorization: Bearer txk_test_8f2a3c9d1e..."

List available scopes

Returns the same scope catalog described in the Authentication section — handy for building a scope-picker UI without hardcoding the list.

curl https://api.txenka.com/api/v1/api-keys/scopes \
  -H "Authorization: Bearer txk_test_8f2a3c9d1e..."

Catalog

A static (but deploy-free updatable) reference of the payment methods, banks and currencies the platform supports.

Payment methods

curl https://api.txenka.com/api/v1/payment-methods \
  -H "Authorization: Bearer txk_test_8f2a3c9d1e..."
mpesa M-Pesa (Vodacom) — direct integration, requires customer_phone
emola e-Mola (Movitel) — direct integration, requires customer_phone
card Card — Visa and Mastercard
bank_transfer_momo Transfer from a mobile wallet to a bank account — requires customer_phone
bank_transfer_b2b Transfer from the customer's own bank account — no customer_phone
bank_transfer_atm Transfer via an ATM — no customer_phone
mpesa_sms M-Pesa via the Android App (SMS relay) — requires customer_phone
emola_sms e-Mola via the Android App (SMS relay) — requires customer_phone
mkesh_sms Mkesh (Millennium bim) via the Android App — only channel available, requires customer_phone

Supported banks

curl https://api.txenka.com/api/v1/banks \
  -H "Authorization: Bearer txk_test_8f2a3c9d1e..."

Supported currencies

curl https://api.txenka.com/api/v1/currencies \
  -H "Authorization: Bearer txk_test_8f2a3c9d1e..."

Stats

Volume summary, counts by state, breakdown by method, and a daily series — the same data that powers the dashboard, for building your own reports.

curl "https://api.txenka.com/api/v1/stats?from=2026-07-01&to=2026-07-30&days=30" \
  -H "Authorization: Bearer txk_test_8f2a3c9d1e..."

Request Logs

History of requests made to the API with this account — method, path, status code, request/response body — handy for debugging an integration without reproducing the request.

curl "https://api.txenka.com/api/v1/logs?status=4xx&method=POST&limit=25" \
  -H "Authorization: Bearer txk_test_8f2a3c9d1e..."

Payment methods

mpesa M-Pesa — Vodacom mobile wallet
emola e-Mola — Movitel mobile wallet
card Card — Visa and Mastercard
bank_transfer Bank transfer

Webhooks

Configure an endpoint under Developers → Webhooks in the dashboard to receive an HTTP POST notification whenever a payment's status changes — without polling the API. The signing secret is only ever shown once, at creation — save it right away.

Main events

payment_intent.succeeded

The payment was confirmed successfully.

payment_intent.failed

The payment failed or was declined.

payment_intent.cancelled

The Payment Intent was cancelled.

Errors

Errors always follow the same shape, with a stable code you can handle programmatically and a human-readable message.

Response
{
  "error": {
    "code": "payment_method_disabled",
    "message": "O método de pagamento 'mpesa' não está activo para esta conta."
  }
}

Need help integrating?

Our team answers technical questions about the API.

Talk to the team