Tranzak Docs
tranzak.co Dashboard
Docs  /  Accept payments

Embedded card widget

Accept Visa and Mastercard payments in a widget embedded on your own page with payment_method card, without redirecting the customer.

With payment_method: "card", the customer enters the card on your page, in a widget provided by Tranzak and powered by Stripe. There is no redirect, and card data never passes through your server or ours.

Access

Mode Availability
Test key (tk_test_) Works immediately. Test freely, widget included.
Live key (tk_live_) Requires approval. Request it from the dashboard: Payment methods → Request access. Until it is approved, live requests answer 403 payment_method_not_approved.

Minimum amount

Stripe refuses card payments below 0.50 USD (about 65 HTG). Tranzak checks this before calling Stripe: below the minimum, the API answers 400 amount_too_low with the exact minimum in message, and no transaction is created.

Read the current minimum in card_minimum of the exchange rate endpoint to disable your pay button before the customer clicks.

1. Create the payment on your server

curl https://api.tranzak.co/api/gateway/v1/payments \
  -H "X-Api-Key: $TRANZAK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 500,
    "currency": "HTG",
    "payment_method": "card",
    "customer_name": "Jean Dupont",
    "customer_email": "[email protected]"
  }'
const res = await fetch('https://api.tranzak.co/api/gateway/v1/payments', {
  method: 'POST',
  headers: { 'X-Api-Key': process.env.TRANZAK_API_KEY, 'Content-Type': 'application/json' },
  body: JSON.stringify({
    amount: 500,
    currency: 'HTG',
    payment_method: 'card',
    customer_name: 'Jean Dupont',
    customer_email: '[email protected]',
  }),
});
const payment = await res.json();
// Send payment.client_secret and payment.publishable_key to your page
import os, requests

payment = requests.post(
    "https://api.tranzak.co/api/gateway/v1/payments",
    headers={"X-Api-Key": os.environ["TRANZAK_API_KEY"]},
    json={
        "amount": 500,
        "currency": "HTG",
        "payment_method": "card",
        "customer_name": "Jean Dupont",
        "customer_email": "[email protected]",
    },
).json()
# Send payment["client_secret"] and payment["publishable_key"] to your page

The response has no payment_url. It returns what the widget needs:

{
  "success": true,
  "transaction_id": "17843268616389",
  "amount": "500.00",
  "currency": "HTG",
  "status": "requires_payment_method",
  "payment_intent_id": "pi_3UJIANGPt6aUvL4Q…",
  "client_secret": "pi_3UJIANGPt6aUvL4Q…_secret_…",
  "publishable_key": "pk_test_…"
}

HTG amounts are converted to USD for Stripe at the rate returned by the exchange rate endpoint.

2. Show the widget on your page

<div id="tranzak-card-element"></div>
<button id="pay-btn">Pay</button>

<script src="https://api.tranzak.co/js/tranzak-card.js"></script>
<script>
  TranzakCard.mount({
    containerId: 'tranzak-card-element',
    clientSecret: payment.client_secret,
    publishableKey: payment.publishable_key,
  });

  document.getElementById('pay-btn').addEventListener('click', function () {
    TranzakCard.confirm({
      onSuccess: function (paymentIntent) { /* update the screen only */ },
      onError: function (error) { /* card declined, show error.message */ },
    });
  });
</script>

Warning onSuccess is an immediate callback from Stripe, not proof of payment. The source of truth is the payment.success webhook or GET /payments/{transaction_id}.

Errors

Card declines are returned with Stripe's customer-safe message. Other provider problems return a generic "temporarily unavailable" message. Show the message to the customer, and let them try another card.

Test cards

With a test key the widget runs in real Stripe test mode. See Sandbox and test mode.