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
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?