ERPNext Credit Card Payment Integration by ERPGulf

Rishal Bazim
Rishal Bazim
May 7, 2026
ERPNext Credit Card Payment Integration by ERPGulf

Seamless payment processing between ERPNext / POS Awesome and GEIDEA credit card terminals via MQTT.

Overview

This project bridges ERPNext (and its POS Awesome module) with GEIDEA credit card machines. When a sale is made, the transaction amount is pushed to the physical credit card terminal over MQTT. The terminal processes the payment and sends the result back directly to the ERPNext server via a REST callback API.

Repositories

Component

Repository

Technology

Backend (ERPNext App)

cardpay_erpgulf

Python / Frappe Framework

Frontend (Android App)

geidea-claudion

Kotlin / Android

Architecture

Flow Summary

Step 1 – POS Awesome initiates payment

The cashier triggers a card payment from POS Awesome, sending transaction details to the Frappe server:

{
  "user": "husna123",
  "amount": 1250.00,
  "invoice_number": "INV-001",
  "customer": "John Doe"
}

Step 2 – Frappe server maps user to device

The Frappe backend looks up the GEIdea Device Map to find the terminal assigned to that user, resolves the device ID and MQTT broker URL, then publishes the payload to the MQTT broker:

{
  "device_id": "CCM-987654",
  "amount": 1250.00,
  "customer": "John Doe",
  "invoice_number": "INV-001",
  "broker_url": "mqtt://broker.example.com:1883"
}

Step 3 – MQTT broker routes message to terminal

The credit card machine subscribes to its dedicated MQTT topic. The broker delivers the payment request, including invoice number and amount, directly to the terminal.

Step 4 – Terminal processes payment & publishes result

The GEIDEA terminal (running the geidea-claudion Android app) processes the card transaction and publishes the result back to the MQTT broker:

{
  "invoice_number": "INV-20250822-001",
  "status": "approved",
  "transaction_id": "TXN-78"
}

Step 5 – Frappe receives result & responds to POS Awesome

The Frappe server picks up the status from the broker, logs the transaction in GEIdea Log, and returns the final result to POS Awesome:

{
  "invoice_number": "INV-20250822-001",
  "status": "approved",
  "transaction_id": "TXN-78"
}

Components

1. Backend – cardpay_erpgulf (Frappe App)

Key Doctypes

Key API Endpoints

send_request_to_device – Request Payload (POS Awesome → Frappe)

{
  "uuid": "unique-transaction-id",
  "user": "cashier@example.com",
  "amount": 100.00,
  "invoice_number": "INV-001",
  "customer": "John Doe",
  "refund": 0,
  "transaction_id": "",
  "posting_date": ""
}

When refund is 1, both transaction_id and posting_date are required.

MQTT Payload (Frappe → MQTT Broker → Terminal)

The Frappe backend forwards the entire request above to the MQTT broker, and appends two additional fields resolved from the GEIdea Device Map:

{
  "uuid": "unique-transaction-id",
  "user": "cashier@example.com",
  "amount": 100.00,
  "invoice_number": "INV-001",
  "customer": "John Doe",
  "refund": 0,
  "transaction_id": "",
  "posting_date": "",
  "device_topic": "5b548bcb1371d319",
  "custom_print_reciept_configuration": 0
}

This full payload is published to the topic matching the terminal's Android ID. The message is also stored in Redis (keyed by uuid) for audit logging.

Return / Refund Invoices

Return invoices are supported. When POS Awesome processes a return, it sets "refund": 1 in the payload along with the transaction_id of the original invoice. The terminal uses this to initiate a refund against that specific transaction rather than a new payment.

Return payload example:

{
  "uuid": "unique-transaction-id",
  "user": "cashier@example.com",
  "amount": 100.00,
  "invoice_number": "RINV-001",
  "customer": "John Doe",
  "callback_url": "https://your-erpnext.com",
  "refund": 1,
  "transaction_id": "TXN-78",
  "posting_date": "2025-08-22",
  "device_topic": "5b548bcb1371d319",
  "custom_print_reciept_configuration": 0
}

Validation rules for refunds:

  • refund: 1 → both transaction_id and posting_date are mandatory. The request will be rejected if either is missing.

  • transaction_id must be the transaction ID from the original approved payment so GEIDEA can match and reverse it.

  • refund: 0transaction_id is ignored.

State Management (Redis)

Redis is used to manage in-flight transaction state and prevent duplicate requests:

The send_request_to_device API polls Redis every second, up to the configured Time-Span (default: 60 s), waiting for the callback to populate a response.

MQTT Configuration (MQTT Setting Doctype)

2. Frontend – geidea-claudion (Android App)

An Android application installed on the GEIDEA credit card terminal. It:

  • Connects to the MQTT broker using credentials entered in its built-in settings page.

  • Subscribes to its own MQTT topic (derived from the device's Android ID) on startup.

  • Receives payment request payloads from ERPNext.

  • Initiates the payment flow on the GEIDEA terminal hardware.

  • Posts the transaction result back to ERPNext via HTTP.

How the App Selects Its MQTT Server

The MQTT broker is not hardcoded. After the app is installed from the GEIDEA App Store, an administrator opens the in-app Settings page and enters the broker details manually:

These credentials are saved on the device and used every time the app starts to establish the MQTT connection.

Important: The MQTT broker details are provided by the Claudion team. Contact support@erpgulf.com to obtain them. Only KSA-hosted, SSL-secured brokers are supported.

⚠️ Inter-App Communication: On the GEIDEA terminal, you must enable inter-app communication in the device settings. Without this, the geidea-claudion app will not be able to communicate with the default MADA payment app on the terminal, and payments will fail.

How the App Knows Which MQTT Topic to Subscribe To

The app subscribes to a topic based on its own Android ID — a unique identifier the device already knows without any external input. This is displayed on the app's main screen (e.g. 5b548bcb1371d319).

On the ERPNext side, this same Android ID is entered into the Device Topic field of the GEIdea Device Map doctype and linked to the cashier user who operates that terminal. This is the one-time manual setup step that ties a physical machine to an ERPNext user.

The map record has three key fields:

In the backend code, this is resolved as:

topic = device_doc.data   # Device Topic field = Android ID = MQTT topic

So when ERPNext receives "user": "husna123" from POS Awesome, it queries the device map, retrieves the Android ID as the topic, and publishes the payment payload to that topic on the broker. The terminal — already subscribed to its own Android ID — receives it instantly.

Cashier user       ──►  GEIdea Device Map  ──►  Android ID   ==  MQTT Topic
(e.g. husna123)         (ERPNext lookup)         (e.g. 5b548bcb1371d319)

Callback API Call (Android → ERPNext)

POST {callback_url}/api/method/geidea_erpgulf.geidea_erpgulf.posaw_test.device_callback
Content-Type: application/json

{
  "uuid": "unique-transaction-id",
  "responseCode": "00",
  "responseMessage": "Approved",
  ...
}

The app uses OkHttp for HTTP and Paho MQTT (or equivalent) for broker communication.

Installation

Backend (ERPNext App)

# From your Frappe bench directory
bench get-app https://github.com/ERPGulf/cardpay_erpgulf
bench --site your-site.com install-app cardpay_erpgulf
bench --site your-site.com migrate

Dependencies:

  • paho-mqtt – MQTT client

  • redis – State management

pip install paho-mqtt redis

Android App

The Android app is not available on the Google Play Store or Apple App Store, and cannot be side-loaded manually onto the terminal.

It is distributed exclusively through the GEIDEA App Store, which is available on GEIDEA-provided terminals only. To get the app installed on your terminal, contact your GEIDEA account representative or reach out to support@erpgulf.com.

Configuration

Step 1 – MQTT Setting (ERPNext)

Navigate to MQTT Setting in ERPNext and fill in:

  • Protocol: ssl

  • Broker Host: your MQTT broker hostname (provided by Claudion — see below)

  • Port: Provided by Claudion team

  • Username / Password: broker credentials (provided by Claudion)

  • Time-Span: polling timeout in seconds (e.g., 60)

Important: The MQTT server is provided by the Claudion team. Contact support@erpgulf.com to request access. Only KSA-hosted, SSL-secured servers are supported — do not use unverified or non-KSA servers.

Step 2 – GEIdea Device Map (ERPNext)

Create a record mapping each cashier user to their terminal's MQTT topic:

Step 3 – CardPay Settings (ERPNext)

Navigate to CardPay Settings → New and configure:

  • Provider: GEIDEA

  • Connection Type: IP

  • Machine IP, Merchant ID, API Key, Secret Key

Step 4 – Android App

Configure the app with:

  • MQTT broker credentials (matching MQTT Setting above)

  • ERPNext server callback URL

Transaction Status

Logging

Every transaction is logged in the GEIdea Log doctype with:

  • uuid – Unique transaction identifier

  • input_response – Original request payload

  • output_response – MQTT publish payload

  • custom_status_ – Full response JSON

  • custom_status_of_paymentApproved / Declined / Timeout

Security Notes

  • The MQTT broker uses SSL/TLS with certificate verification.

  • ERPNext stores the MQTT password using Frappe's encrypted password field (get_password).

  • The device_callback endpoint is open (allow_guest=True) since terminals do not have ERPNext sessions; validate by UUID and short TTL to mitigate abuse.

  • Redis keys auto-expire after 60 seconds to prevent stale state.

Supported Payment Cards

Accepted card schemes are determined by each merchant's individual arrangement with GEIDEA. Generally, MADA cards are accepted by default. Support for Visa, Mastercard, and other international schemes depends on your GEIDEA account setup. Contact your GEIDEA account manager for details.

License & Copyright

This software is proprietary and copyright protected. It is not open-source.

© ERPGulf & Claudion. All rights reserved. Unauthorized copying, distribution, or modification is strictly prohibited.

For licensing inquiries, visit erpgulf.com or claudion.com.

Contact

Support

support@erpgulf.com

Sales

sales@erpgulf.com

Website

erpgulf.com · claudion.com

Rishal Bazim
Written by Rishal Bazim