Tamara Payment Gateway

The TamaraPaymentGateway component enables seamless integration of the Tamara payment method into your e-commerce checkout experience. Designed for the Akinon ProjectZero ecosystem, this extension provides a secure, localized, and fully customizable payment flow for merchants using Tamara as a payment provider.

With support for custom rendering via the renderer prop, you can tailor the user interface to match your brand's requirements, while still benefiting from Tamara’s robust backend logic, including availability checks, secure hash validation, and auto-submitting forms.

This guide will walk you through installation, implementation, prop configuration, UI customization, and API integration to help you get up and running quickly with Tamara in your checkout process.

Installation Method

You can use the following command to install the extension with the latest plugins:

npx @akinon/projectzero@latest --plugins

Usage

Navigate to your payment gateway route:

src/app/[commerce]/[locale]/[currency]/payment-gateway/tamara/page.tsx

Create page.tsx:

import { TamaraPaymentGateway } from '@akinon/pz-tamara-extension';

const TamaraGateway = async ({
  searchParams: { sessionId },
  params: { currency, locale }
}: {
  searchParams: Record<string, string>;
  params: { currency: string; locale: string };
}) => {
  return (
    <TamaraPaymentGateway
      sessionId={sessionId}
      currency={currency}
      locale={locale}
      extensionUrl={process.env.TAMARA_EXTENSION_URL}
      hashKey={process.env.TAMARA_HASH_KEY}
    />
  );
};

export default TamaraGateway;

Props

Prop
Type
Required
Description

sessionId

string

Yes

Session ID of the current checkout/payment flow.

currency

string

Yes

Active currency (e.g., "AED").

locale

string

Yes

Active locale (e.g., "en", "ar").

extensionUrl

string

Yes

URL of the Tamara extension endpoint.

hashKey

string

Yes

Secret hash key for request/response validation.

renderer

TamaraRendererProps

Optional

Object with custom render methods for UI customization.

Customizing the Tamara Component

Example usage of renderer prop:

<TamaraPaymentGateway
  sessionId={sessionId}
  currency={currency}
  locale={locale}
  extensionUrl={process.env.TAMARA_EXTENSION_URL}
  hashKey={process.env.TAMARA_HASH_KEY}
  renderer={{
    formComponent: {
      renderForm: ({ extensionUrl, sessionId, context, csrfToken, autoSubmit }) => (
        <div className="custom-tamara-form-wrapper">
          <h3 className="text-lg font-semibold mb-4">Tamara Payment</h3>
          <p className="mb-4">You are being redirected to Tamara payment page...</p>
          <form
            action={`${extensionUrl}/form-page/?sessionId=${sessionId}`}
            method="post"
            encType="multipart/form-data"
            id="tamara-custom-form"
            className="hidden"
          >
            <input type="hidden" name="csrf_token" value={csrfToken} />
            <input type="hidden" name="data" value={JSON.stringify(context)} />
            {autoSubmit && (
              <script
                dangerouslySetInnerHTML={{
                  __html: "document.getElementById('tamara-custom-form').submit()"
                }}
              />
            )}
          </form>
          <div className="loader w-12 h-12 border-4 border-t-4 border-gray-200 border-t-blue-500 rounded-full animate-spin"></div>
        </div>
      )
    },
    paymentGateway: {
      renderContainer: ({ children }) => (
        <div className="p-8 max-w-lg mx-auto bg-white rounded-lg shadow-md">
          {children}
        </div>
      )
    }
  }}
/>

Renderer API

interface TamaraRendererProps {
  formComponent?: {
    renderForm?: (props: {
      extensionUrl: string;
      sessionId: string;
      context: any;
      csrfToken: string;
      autoSubmit: boolean;
    }) => React.ReactNode;
    renderLoading?: () => React.ReactNode;
    renderError?: (error: string) => React.ReactNode;
  };
  paymentGateway?: {
    renderContainer?: (props: { children: React.ReactNode }) => React.ReactNode;
  };
}

API Routes

Check Availability API

Create the following file:

src/app/api/tamara-check-availability/route.ts
import { POST } from '@akinon/pz-tamara-extension/src/pages/api/check-availability';

export { POST };

This route handles Tamara availability checks for:

  • Country

  • Phone number

  • Order amount

  • Currency

The logic is secured with hash verification.

Availability Check (Redux Hook)

Use the following mutation to check Tamara availability:

import { useCheckTamaraAvailabilityMutation } from '@akinon/pz-tamara-extension/src/redux/api';

const YourComponent = () => {
  const [checkTamaraAvailability] = useCheckTamaraAvailabilityMutation();
  const [isTamaraAvailable, setIsTamaraAvailable] = useState(false);

  useEffect(() => {
    const checkAvailability = async () => {
      try {
        const response = await checkTamaraAvailability({
          country: 'AE',
          phone_number: '+971123456789',
          order_amount: 1000
        }).unwrap();

        setIsTamaraAvailable(response.has_availability);
      } catch (error) {
        console.error('Error checking Tamara availability:', error);
        setIsTamaraAvailable(false);
      }
    };

    checkAvailability();
  }, [checkTamaraAvailability]);

  return (
    // Render conditionally
  );
};

Response Fields

  • has_availability : boolean

  • salt : string

  • hash : string

Configuration

Add the following environment variables to your .env file:

TAMARA_EXTENSION_URL=<your_extension_url>
TAMARA_HASH_KEY=<your_hash_key>

Last updated

Was this helpful?