A powerful, developer-friendly PHP SDK for seamless integration with Jordan's electronic tax invoicing system (JoFotara). This package provides:
- 🚀 Simple, Fluent API: Intuitive builder pattern for creating invoices
- ✅ Full UBL 2.1 Compliance: Generates valid XML according to Jordan Tax Authority standards
- 🔒 Built-in Validation: Ensures all required fields and business rules are satisfied
- 🔄 Multiple Invoice Types: Support for sales, income, credit invoices, and more
- 💳 Flexible Payment Methods: Handle both cash and receivable transactions
- 🧮 Automatic Calculations: Built-in tax and total calculations
composer require jafar-albadarneh/jofotarause JBadarneh\JoFotara\JoFotaraService;
$invoice = new JoFotaraService('your-client-id', 'your-client-secret');
// Create a basic sales invoice
$invoice->basicInformation()
->setInvoiceId('INV-001')
->setUuid('123e4567-e89b-12d3-a456-426614174000')
->setIssueDate('16-02-2025')
->setInvoiceType('general_sales')
->cash();
$invoice->sellerInformation()
->setName('Your Company')
->setTin('123456789');
$invoice->customerInformation()
->setId('987654321', 'TIN')
->setName('Customer Name');
$invoice->items()
->addItem('1')
->setQuantity(2)
->setUnitPrice(100.0)
->setDescription('Premium Widget')
->tax(16);
$response = $invoice->send();The SDK supports all JoFotara invoice types:
// 1. General Sales Invoice
$invoice->basicInformation()
->setInvoiceType('general_sales')
->cash(); // or ->receivable()
// 2. Special Sales Invoice (e.g., exports)
$invoice->basicInformation()
->setInvoiceType('special_sales')
->cash();
// 3. Income Invoice
$invoice->basicInformation()
->setInvoiceType('income')
->cash();
// 4. Credit Invoice (for returns/corrections)
$invoice->basicInformation()
->setInvoiceType('general_sales')
->cash()
->asCreditInvoice(
originalInvoiceId: 'INV-001',
originalInvoiceUuid: '123e4567-...',
originalFullAmount: 200.00
);
// Set reason for credit invoice
$invoice->setReasonForReturn('Defective item returned');JoFotara supports two payment methods:
// 1. Cash Payment (code: 012)
$invoice->basicInformation()
->setInvoiceType('general_sales')
->cash();
// 2. Receivable Payment (code: 022)
$invoice->basicInformation()
->setInvoiceType('general_sales')
->receivable();The SDK supports various tax scenarios:
// 1. Standard VAT (16%)
$invoice->items()
->addItem('1')
->setQuantity(1)
->setUnitPrice(100.0)
->tax(16);
// 2. Tax Exempt
$invoice->items()
->addItem('2')
->setQuantity(1)
->setUnitPrice(50.0)
->taxExempted();
// 3. Zero-rated (e.g., exports)
$invoice->items()
->addItem('3')
->setQuantity(1)
->setUnitPrice(75.0)
->zeroTax();
// 4. Item with Discount
$invoice->items()
->addItem('4')
->setQuantity(1)
->setUnitPrice(200.0)
->setDiscount(20.0)
->tax(16);$response = $invoice->send();
if ($response->isSuccessful()) {
// Invoice accepted
$data = $response->getData();
echo "Invoice ID: {$data['invoice_id']}\n";
echo "Status: {$data['status']}\n";
} else {
// Handle errors
foreach ($response->getErrors() as $error) {
echo "Error: {$error['message']}\n";
}
}Important: JoFotara does not provide a sandbox environment. For testing:
- You need a registered entity with Jordan Tax Department
- Your entity must be registered for JoFotara
- Use past dates for test invoices
- Always issue credit invoices to reverse test transactions
# Run the test suite
composer test
# Generate a test invoice
php examples/GenerateGeneralInvoice.php
# On macOS, copy to clipboard
php examples/GenerateGeneralInvoice.php | pbcopyNever commit your JoFotara credentials to version control. Use environment variables:
$invoice = new JoFotaraService(
clientId: getenv('JOFOTARA_CLIENT_ID'),
clientSecret: getenv('JOFOTARA_CLIENT_SECRET')
);The MIT License (MIT). Please see the License File for more information.
$invoice->basicInformation()
->setInvoiceId('INV-001') // Required: Your unique invoice ID
->setUuid('123e4567-...') // Required: UUID v4 format
->setIssueDate('16-02-2025') // Required: Format dd-mm-yyyy
->cash() // Payment method: cash (012)
// or
->receivable() // Payment method: receivable (022)
->setNote('Optional note') // Optional: Invoice note
->setInvoiceCounter(1); // Optional: Sequential counter (ICV)// Configure default seller info (recommended)
SellerInformation::configureDefaults(
tin: '123456789',
name: 'Your Company'
);
// Or set per invoice
$invoice->sellerInformation()
->setName('Your Company') // Required: Company name
->setTin('123456789'); // Required: Tax ID Number$invoice->customerInformation()
->setId('987654321', 'TIN') // Required: ID and type (TIN, NIN, or PN)
->setName('Customer Name') // Required for receivables
->setPostalCode('11937') // Optional
->setCityCode('JO-IR') // Optional: Jordan city code
->setPhone('0791234567') // Optional
->setTin('987654321'); // OptionalThe supplier income source sequence (تسلسل مصدر الدخل) is a required value that must be set for each invoice. This value is obtained from your JoFotara portal and represents your business's income source sequence number.
// Set the supplier income source sequence
$invoice->supplierIncomeSource('123456789');Important: The supplier income source sequence is mandatory and must be set before generating the invoice XML. You can find this value in the table where it shows your client ID and secret, under column "تسلسل مصدر الدخل".
Example usage in a complete invoice:
$invoice = new JoFotaraService('your-client-id', 'your-client-secret');
// Set basic information
$invoice->basicInformation()
->setInvoiceId('INV-001')
->setIssueDate('2024-03-20')
->cash();
// Set seller information
$invoice->sellerInformation()
->setName('Your Company')
->setTin('123456789');
// Set buyer information
$invoice->customerInformation()
->setId('987654321', 'TIN')
->setName('Customer Name');
// Set supplier income source (required)
$invoice->supplierIncomeSource('123456789');
// Add items...
$invoice->items()
->addItem('1')
->setQuantity(1)
->setUnitPrice(100.0)
->setDescription('Product')
->tax(16);The supplier income source sequence is used by the JoFotara system to:
- Track your business's income sources
- Validate invoice submissions
- Ensure proper tax reporting
// Standard VAT item (16%)
$invoice->items()
->addItem('1')
->setQuantity(2)
->setUnitPrice(100.0)
->setDescription('Premium Widget')
->tax(16);
// Tax exempt item
$invoice->items()
->addItem('2')
->setQuantity(1)
->setUnitPrice(50.0)
->setDescription('Basic Widget')
->taxExempted();
// Zero-rated item (e.g., exports)
$invoice->items()
->addItem('3')
->setQuantity(1)
->setUnitPrice(75.0)
->setDescription('Export Widget')
->zeroTax();
// Item with discount
$invoice->items()
->addItem('4')
->setQuantity(1)
->setUnitPrice(200.0)
->setDescription('Discounted Widget')
->setDiscount(20.0) // 20 JOD discount
->tax(16);The SDK automatically calculates all invoice totals based on the items you add:
- Tax exclusive amount (before tax)
- Tax inclusive amount (after tax)
- Total discounts
- Total tax amount
- Final payable amount
Automatic calculations are applied once you call ->invoiceTotals(). This method must be called after all items have been added.
For special cases, you can manually set totals:
$invoice->invoiceTotals()
->setTaxExclusiveAmount(100.0)
->setTaxInclusiveAmount(92.8)
->setDiscountTotalAmount(20.0)
->setTaxTotalAmount(12.8)
->setPayableAmount(92.8);Note: When manually setting totals, they must match the calculated values from the items, or an exception will be thrown to ensure data integrity.
If you need to use totals that differ from the calculated values (e.g., due to external business logic, special rounding rules, or integration with other systems), you can disable totals validation:
// Disable totals validation to allow custom values
$invoice->disableTotalsValidation();
// Set custom totals that may differ from calculated values
$invoice->invoiceTotals()
->setTaxExclusiveAmount(230.0) // Custom amount
->setTaxInclusiveAmount(260.0) // Custom amount
->setTaxTotalAmount(30.0) // Custom amount
->setPayableAmount(260.0); // Custom amount
// Generate XML with custom totals
$xml = $invoice->generateXml();
// Re-enable validation if needed
$invoice->enableTotalsValidation();Alternative methods for controlling validation:
// Using setTotalsValidation method
$invoice->setTotalsValidation(false); // Disable
$invoice->setTotalsValidation(true); // Enable
// Method chaining is supported
$invoice->disableTotalsValidation()
->invoiceTotals()
->setTaxExclusiveAmount(100.0);Important: Disabling validation only affects the cross-validation between totals and line items. Individual field validation (e.g., negative amounts) still applies.
The send() method handles the complete flow:
- XML generation and validation
- Base64 encoding
- API authentication
- Error handling
try {
$response = $invoice->send();
$qrCode = $response['qrCode'];
} catch (InvalidArgumentException $e) {
// Handle validation errors
echo $e->getMessage();
} catch (RuntimeException $e) {
// Handle API communication errors
echo $e->getMessage();
}The SDK includes comprehensive validation to ensure your invoice meets JoFotara requirements:
- All required fields are present and properly formatted
- Date formats follow dd-mm-yyyy pattern
- Tax calculations are accurate and consistent
- Totals match line items
- Valid city codes and tax categories
Validation errors throw InvalidArgumentException with descriptive messages to help you quickly identify and fix issues.
vendor/bin/pestContributions are welcome! Please see CONTRIBUTING for details.
If you discover any security-related issues, please email security@jbadarneh.com instead of using the issue tracker.
The MIT License (MIT). Please see License File for more information.