Skip to content

Complete Flow Example

Here's a complete working example that you can copy and run. This script creates a buyer, creates an invoice, validates it, submits to LHDN, and retrieves the QR code.

Before Running

Replace your-api-token-here with your actual API token from the InvoisX dashboard.

javascript
/**
 * InvoisX Complete Flow Example
 *
 * Run with: node complete-flow.js
 */

const fs = require('fs');

const API_URL = 'https://invoisx.com/api/v1';
const API_TOKEN = 'your-api-token-here';

async function api(method, endpoint, data = null) {
  const options = {
    method,
    headers: {
      'Authorization': `Bearer ${API_TOKEN}`,
      'Accept': 'application/json',
      'Content-Type': 'application/json',
    },
  };

  if (data) {
    options.body = JSON.stringify(data);
  }

  const response = await fetch(`${API_URL}${endpoint}`, options);
  const json = await response.json();

  if (!response.ok) {
    throw new Error(json.message || 'API request failed');
  }

  return json;
}

async function main() {
  console.log('=== InvoisX Complete Flow ===\n');

  // Step 1: Create Buyer
  console.log('Step 1: Creating buyer...');
  const buyer = await api('POST', '/buyers', {
    name: 'Example Trading Pte Ltd',
    tin: 'EI00000000020',
    id_type: 'PASSPORT',
    id_value: 'A12345678',
    address: {
      line1: '123 Orchard Road',
      city: 'Singapore',
      state: '17',
      postCode: '238867',
      countryCode: 'SGP',
    },
    contact: {
      phone: '+6591234567',
      email: 'billing@example.sg',
    },
  });
  const buyerId = buyer.data.id;
  console.log(`Created buyer: ${buyerId}\n`);

  // Step 2: Create Invoice
  console.log('Step 2: Creating invoice...');
  const invoice = await api('POST', '/invoices', {
    buyerId: buyerId,
    invoiceSerialNumber: `INV-${Date.now()}`,
    currencyCode: 'MYR',
    autoCalculate: true,
    invoiceLines: [
      {
        classifications: ['001'],
        productDescription: 'Consulting Services',
        quantity: 10,
        unitCode: 'H87',
        unitPrice: 500.00,
        invoiceLineTaxes: [
          { taxType: '01', taxRate: 8 },
        ],
      },
    ],
  });
  const invoiceId = invoice.data.id;
  const payable = invoice.data.payableAmount;
  console.log(`Created invoice: ${invoiceId} (RM ${payable})\n`);

  // Step 3: Validate
  console.log('Step 3: Validating invoice...');
  const validation = await api('POST', `/documents/${invoiceId}/validate`);
  console.log(`Validation: ${validation.data.status}\n`);

  // Step 4: Submit to LHDN
  console.log('Step 4: Submitting to LHDN...');
  const submission = await api('POST', `/documents/${invoiceId}/submit`);
  const documentUuid = submission.data.document_uuid;
  console.log(`Submitted! LHDN UUID: ${documentUuid}\n`);

  // Step 5: Check Status
  console.log('Step 5: Checking LHDN status...');
  let status = 'Submitted';
  let attempts = 0;

  while (status === 'Submitted' && attempts < 10) {
    await new Promise(resolve => setTimeout(resolve, 2000));
    attempts++;

    const statusCheck = await api('GET', `/documents/${invoiceId}/status`);
    status = statusCheck.data.status;
    console.log(`Attempt ${attempts}: ${status}`);
  }
  console.log();

  // Step 6: Get QR Code
  if (status === 'Valid') {
    console.log('Step 6: Getting QR code...');
    const qr = await api('GET', `/documents/${invoiceId}/qr`);
    console.log(`Verification URL: ${qr.data.verification_url}`);

    const qrData = qr.data.qr_code.replace('data:image/png;base64,', '');
    fs.writeFileSync('invoice-qr.png', Buffer.from(qrData, 'base64'));
    console.log('QR code saved to: invoice-qr.png');
  }

  console.log('\n=== Complete! ===');
}

main().catch(console.error);
python
"""
InvoisX Complete Flow Example

Run with: python complete_flow.py
"""

import requests
import time
import base64

API_URL = 'https://invoisx.com/api/v1'
API_TOKEN = 'your-api-token-here'

headers = {
    'Authorization': f'Bearer {API_TOKEN}',
    'Accept': 'application/json',
    'Content-Type': 'application/json',
}


def api(method, endpoint, data=None):
    url = f'{API_URL}{endpoint}'
    response = requests.request(method, url, headers=headers, json=data)

    if not response.ok:
        raise Exception(response.json().get('message', 'API request failed'))

    return response.json()


def main():
    print('=== InvoisX Complete Flow ===\n')

    # Step 1: Create Buyer
    print('Step 1: Creating buyer...')
    buyer = api('POST', '/buyers', {
        'name': 'Example Trading Pte Ltd',
        'tin': 'EI00000000020',
        'id_type': 'PASSPORT',
        'id_value': 'A12345678',
        'address': {
            'line1': '123 Orchard Road',
            'city': 'Singapore',
            'state': '17',
            'postCode': '238867',
            'countryCode': 'SGP',
        },
        'contact': {
            'phone': '+6591234567',
            'email': 'billing@example.sg',
        },
    })
    buyer_id = buyer['data']['id']
    print(f'Created buyer: {buyer_id}\n')

    # Step 2: Create Invoice
    print('Step 2: Creating invoice...')
    invoice = api('POST', '/invoices', {
        'buyerId': buyer_id,
        'invoiceSerialNumber': f'INV-{int(time.time())}',
        'currencyCode': 'MYR',
        'autoCalculate': True,
        'invoiceLines': [
            {
                'classifications': ['001'],
                'productDescription': 'Consulting Services',
                'quantity': 10,
                'unitCode': 'H87',
                'unitPrice': 500.00,
                'invoiceLineTaxes': [
                    {'taxType': '01', 'taxRate': 8},
                ],
            },
        ],
    })
    invoice_id = invoice['data']['id']
    payable = invoice['data']['payableAmount']
    print(f'Created invoice: {invoice_id} (RM {payable})\n')

    # Step 3: Validate
    print('Step 3: Validating invoice...')
    validation = api('POST', f'/documents/{invoice_id}/validate')
    print(f"Validation: {validation['data']['status']}\n")

    # Step 4: Submit to LHDN
    print('Step 4: Submitting to LHDN...')
    submission = api('POST', f'/documents/{invoice_id}/submit')
    document_uuid = submission['data']['document_uuid']
    print(f'Submitted! LHDN UUID: {document_uuid}\n')

    # Step 5: Check Status
    print('Step 5: Checking LHDN status...')
    status = 'Submitted'
    attempts = 0

    while status == 'Submitted' and attempts < 10:
        time.sleep(2)
        attempts += 1

        status_check = api('GET', f'/documents/{invoice_id}/status')
        status = status_check['data']['status']
        print(f'Attempt {attempts}: {status}')

    print()

    # Step 6: Get QR Code
    if status == 'Valid':
        print('Step 6: Getting QR code...')
        qr = api('GET', f'/documents/{invoice_id}/qr')
        print(f"Verification URL: {qr['data']['verification_url']}")

        qr_data = qr['data']['qr_code'].replace('data:image/png;base64,', '')
        with open('invoice-qr.png', 'wb') as f:
            f.write(base64.b64decode(qr_data))
        print('QR code saved to: invoice-qr.png')

    print('\n=== Complete! ===')


if __name__ == '__main__':
    main()
php
<?php
/**
 * InvoisX Complete Flow Example (Laravel)
 *
 * Add to a route or run with: php artisan tinker < complete_flow.php
 */

use Illuminate\Support\Facades\Http;

$apiUrl = 'https://invoisx.com/api/v1';
$apiToken = 'your-api-token-here';

$api = Http::withToken($apiToken)
    ->accept('application/json')
    ->contentType('application/json')
    ->baseUrl($apiUrl);

echo "=== InvoisX Complete Flow ===\n\n";

// Step 1: Create Buyer
echo "Step 1: Creating buyer...\n";
$response = $api->post('/buyers', [
    'name' => 'Example Trading Pte Ltd',
    'tin' => 'EI00000000020',
    'id_type' => 'PASSPORT',
    'id_value' => 'A12345678',
    'address' => [
        'line1' => '123 Orchard Road',
        'city' => 'Singapore',
        'state' => '17',
        'postCode' => '238867',
        'countryCode' => 'SGP',
    ],
    'contact' => [
        'phone' => '+6591234567',
        'email' => 'billing@example.sg',
    ],
]);

if ($response->failed()) {
    throw new Exception("Failed to create buyer: " . $response->body());
}

$buyerId = $response->json('data.id');
echo "Created buyer: $buyerId\n\n";

// Step 2: Create Invoice
echo "Step 2: Creating invoice...\n";
$response = $api->post('/invoices', [
    'buyerId' => $buyerId,
    'invoiceSerialNumber' => 'INV-' . time(),
    'currencyCode' => 'MYR',
    'autoCalculate' => true,
    'invoiceLines' => [
        [
            'classifications' => ['001'],
            'productDescription' => 'Consulting Services',
            'quantity' => 10,
            'unitCode' => 'H87',
            'unitPrice' => 500.00,
            'invoiceLineTaxes' => [
                ['taxType' => '01', 'taxRate' => 8],
            ],
        ],
    ],
]);

if ($response->failed()) {
    throw new Exception("Failed to create invoice: " . $response->body());
}

$invoiceId = $response->json('data.id');
$payable = $response->json('data.payableAmount');
echo "Created invoice: $invoiceId (RM $payable)\n\n";

// Step 3: Validate
echo "Step 3: Validating invoice...\n";
$response = $api->post("/documents/$invoiceId/validate");
$status = $response->json('data.status');
echo "Validation: $status\n\n";

// Step 4: Submit to LHDN
echo "Step 4: Submitting to LHDN...\n";
$response = $api->post("/documents/$invoiceId/submit");
$documentUuid = $response->json('data.document_uuid');
echo "Submitted! LHDN UUID: $documentUuid\n\n";

// Step 5: Check Status
echo "Step 5: Checking LHDN status...\n";
$status = 'Submitted';
$attempts = 0;

while ($status === 'Submitted' && $attempts < 10) {
    sleep(2);
    $attempts++;

    $response = $api->get("/documents/$invoiceId/status");
    $status = $response->json('data.status');
    echo "Attempt $attempts: $status\n";
}
echo "\n";

// Step 6: Get QR Code
if ($status === 'Valid') {
    echo "Step 6: Getting QR code...\n";
    $response = $api->get("/documents/$invoiceId/qr");

    echo "Verification URL: " . $response->json('data.verification_url') . "\n";

    $qrData = str_replace('data:image/png;base64,', '', $response->json('data.qr_code'));
    file_put_contents('invoice-qr.png', base64_decode($qrData));
    echo "QR code saved to: invoice-qr.png\n";
}

echo "\n=== Complete! ===\n";
php
<?php
/**
 * InvoisX Complete Flow Example (Guzzle)
 *
 * Run with: php complete_flow.php
 */

require_once 'vendor/autoload.php';

use GuzzleHttp\Client;

$apiUrl = 'https://invoisx.com/api/v1/';  // Trailing slash required for Guzzle
$apiToken = 'your-api-token-here';

$client = new Client([
    'base_uri' => $apiUrl,
    'headers' => [
        'Authorization' => 'Bearer ' . $apiToken,
        'Accept' => 'application/json',
        'Content-Type' => 'application/json',
    ],
]);

function api($client, $method, $endpoint, $data = null) {
    $options = [];
    if ($data) {
        $options['json'] = $data;
    }

    $response = $client->request($method, $endpoint, $options);
    return json_decode($response->getBody(), true);
}

echo "=== InvoisX Complete Flow ===\n\n";

// Step 1: Create Buyer
echo "Step 1: Creating buyer...\n";
$buyer = api($client, 'POST', '/buyers', [
    'name' => 'Example Trading Pte Ltd',
    'tin' => 'EI00000000020',
    'id_type' => 'PASSPORT',
    'id_value' => 'A12345678',
    'address' => [
        'line1' => '123 Orchard Road',
        'city' => 'Singapore',
        'state' => '17',
        'postCode' => '238867',
        'countryCode' => 'SGP',
    ],
    'contact' => [
        'phone' => '+6591234567',
        'email' => 'billing@example.sg',
    ],
]);
$buyerId = $buyer['data']['id'];
echo "Created buyer: $buyerId\n\n";

// Step 2: Create Invoice
echo "Step 2: Creating invoice...\n";
$invoice = api($client, 'POST', '/invoices', [
    'buyerId' => $buyerId,
    'invoiceSerialNumber' => 'INV-' . time(),
    'currencyCode' => 'MYR',
    'autoCalculate' => true,
    'invoiceLines' => [
        [
            'classifications' => ['001'],
            'productDescription' => 'Consulting Services',
            'quantity' => 10,
            'unitCode' => 'H87',
            'unitPrice' => 500.00,
            'invoiceLineTaxes' => [
                ['taxType' => '01', 'taxRate' => 8],
            ],
        ],
    ],
]);
$invoiceId = $invoice['data']['id'];
$payable = $invoice['data']['payableAmount'];
echo "Created invoice: $invoiceId (RM $payable)\n\n";

// Step 3: Validate
echo "Step 3: Validating invoice...\n";
$validation = api($client, 'POST', "/documents/$invoiceId/validate");
echo "Validation: {$validation['data']['status']}\n\n";

// Step 4: Submit to LHDN
echo "Step 4: Submitting to LHDN...\n";
$submission = api($client, 'POST', "/documents/$invoiceId/submit");
$documentUuid = $submission['data']['document_uuid'];
echo "Submitted! LHDN UUID: $documentUuid\n\n";

// Step 5: Check Status
echo "Step 5: Checking LHDN status...\n";
$status = 'Submitted';
$attempts = 0;

while ($status === 'Submitted' && $attempts < 10) {
    sleep(2);
    $attempts++;

    $statusCheck = api($client, 'GET', "/documents/$invoiceId/status");
    $status = $statusCheck['data']['status'];
    echo "Attempt $attempts: $status\n";
}
echo "\n";

// Step 6: Get QR Code
if ($status === 'Valid') {
    echo "Step 6: Getting QR code...\n";
    $qr = api($client, 'GET', "/documents/$invoiceId/qr");

    echo "Verification URL: {$qr['data']['verification_url']}\n";

    $qrData = str_replace('data:image/png;base64,', '', $qr['data']['qr_code']);
    file_put_contents('invoice-qr.png', base64_decode($qrData));
    echo "QR code saved to: invoice-qr.png\n";
}

echo "\n=== Complete! ===\n";
java
/**
 * InvoisX Complete Flow Example
 *
 * Compile and run with:
 * javac -cp gson.jar CompleteFlow.java
 * java -cp .:gson.jar CompleteFlow
 */

import java.net.http.*;
import java.net.URI;
import java.nio.file.*;
import java.util.Base64;
import com.google.gson.*;

public class CompleteFlow {
    private static final String API_URL = "https://invoisx.com/api/v1";
    private static final String API_TOKEN = "your-api-token-here";
    private static final HttpClient client = HttpClient.newHttpClient();
    private static final Gson gson = new Gson();

    public static void main(String[] args) throws Exception {
        System.out.println("=== InvoisX Complete Flow ===\n");

        // Step 1: Create Buyer
        System.out.println("Step 1: Creating buyer...");
        String buyerJson = """
        {
            "name": "Example Trading Pte Ltd",
            "tin": "EI00000000020",
            "id_type": "PASSPORT",
            "id_value": "A12345678",
            "address": {
                "line1": "123 Orchard Road",
                "city": "Singapore",
                "state": "17",
                "postCode": "238867",
                "countryCode": "SGP"
            },
            "contact": {
                "phone": "+6591234567",
                "email": "billing@example.sg"
            }
        }
        """;
        JsonObject buyer = post("/buyers", buyerJson);
        String buyerId = buyer.getAsJsonObject("data").get("id").getAsString();
        System.out.println("Created buyer: " + buyerId + "\n");

        // Step 2: Create Invoice
        System.out.println("Step 2: Creating invoice...");
        String invoiceJson = String.format("""
        {
            "buyerId": "%s",
            "invoiceSerialNumber": "INV-%d",
            "currencyCode": "MYR",
            "autoCalculate": true,
            "invoiceLines": [{
                "classifications": ["001"],
                "productDescription": "Consulting Services",
                "quantity": 10,
                "unitCode": "H87",
                "unitPrice": 500.00,
                "invoiceLineTaxes": [{"taxType": "01", "taxRate": 8}]
            }]
        }
        """, buyerId, System.currentTimeMillis());
        JsonObject invoice = post("/invoices", invoiceJson);
        String invoiceId = invoice.getAsJsonObject("data").get("id").getAsString();
        String payable = invoice.getAsJsonObject("data").get("payableAmount").getAsString();
        System.out.println("Created invoice: " + invoiceId + " (RM " + payable + ")\n");

        // Step 3: Validate
        System.out.println("Step 3: Validating invoice...");
        JsonObject validation = post("/documents/" + invoiceId + "/validate", null);
        System.out.println("Validation: " + validation.getAsJsonObject("data").get("status") + "\n");

        // Step 4: Submit to LHDN
        System.out.println("Step 4: Submitting to LHDN...");
        JsonObject submission = post("/documents/" + invoiceId + "/submit", null);
        String documentUuid = submission.getAsJsonObject("data").get("document_uuid").getAsString();
        System.out.println("Submitted! LHDN UUID: " + documentUuid + "\n");

        // Step 5: Check Status
        System.out.println("Step 5: Checking LHDN status...");
        String status = "Submitted";
        int attempts = 0;

        while (status.equals("Submitted") && attempts < 10) {
            Thread.sleep(2000);
            attempts++;

            JsonObject statusCheck = get("/documents/" + invoiceId + "/status");
            status = statusCheck.getAsJsonObject("data").get("status").getAsString();
            System.out.println("Attempt " + attempts + ": " + status);
        }
        System.out.println();

        // Step 6: Get QR Code
        if (status.equals("Valid")) {
            System.out.println("Step 6: Getting QR code...");
            JsonObject qr = get("/documents/" + invoiceId + "/qr");
            System.out.println("Verification URL: " +
                qr.getAsJsonObject("data").get("verification_url").getAsString());

            String qrData = qr.getAsJsonObject("data").get("qr_code").getAsString()
                .replace("data:image/png;base64,", "");
            Files.write(Path.of("invoice-qr.png"), Base64.getDecoder().decode(qrData));
            System.out.println("QR code saved to: invoice-qr.png");
        }

        System.out.println("\n=== Complete! ===");
    }

    private static JsonObject post(String endpoint, String body) throws Exception {
        var builder = HttpRequest.newBuilder()
            .uri(URI.create(API_URL + endpoint))
            .header("Authorization", "Bearer " + API_TOKEN)
            .header("Accept", "application/json")
            .header("Content-Type", "application/json");

        if (body != null) {
            builder.POST(HttpRequest.BodyPublishers.ofString(body));
        } else {
            builder.POST(HttpRequest.BodyPublishers.noBody());
        }

        var response = client.send(builder.build(), HttpResponse.BodyHandlers.ofString());
        return JsonParser.parseString(response.body()).getAsJsonObject();
    }

    private static JsonObject get(String endpoint) throws Exception {
        var request = HttpRequest.newBuilder()
            .uri(URI.create(API_URL + endpoint))
            .header("Authorization", "Bearer " + API_TOKEN)
            .header("Accept", "application/json")
            .GET()
            .build();

        var response = client.send(request, HttpResponse.BodyHandlers.ofString());
        return JsonParser.parseString(response.body()).getAsJsonObject();
    }
}
csharp
/**
 * InvoisX Complete Flow Example
 *
 * Run with: dotnet run
 */

using System.Net.Http.Json;
using System.Text.Json;

const string API_URL = "https://invoisx.com/api/v1";
const string API_TOKEN = "your-api-token-here";

using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {API_TOKEN}");
client.DefaultRequestHeaders.Add("Accept", "application/json");

Console.WriteLine("=== InvoisX Complete Flow ===\n");

// Step 1: Create Buyer
Console.WriteLine("Step 1: Creating buyer...");
var buyerData = new {
    name = "Example Trading Pte Ltd",
    tin = "EI00000000020",
    id_type = "PASSPORT",
    id_value = "A12345678",
    address = new {
        line1 = "123 Orchard Road",
        city = "Singapore",
        state = "17",
        postCode = "238867",
        countryCode = "SGP"
    },
    contact = new {
        phone = "+6591234567",
        email = "billing@example.sg"
    }
};

var response = await client.PostAsJsonAsync($"{API_URL}/buyers", buyerData);
var buyer = await response.Content.ReadFromJsonAsync<JsonElement>();
var buyerId = buyer.GetProperty("data").GetProperty("id").GetString();
Console.WriteLine($"Created buyer: {buyerId}\n");

// Step 2: Create Invoice
Console.WriteLine("Step 2: Creating invoice...");
var invoiceData = new {
    buyerId = buyerId,
    invoiceSerialNumber = $"INV-{DateTimeOffset.UtcNow.ToUnixTimeSeconds()}",
    currencyCode = "MYR",
    autoCalculate = true,
    invoiceLines = new[] {
        new {
            classifications = new[] { "001" },
            productDescription = "Consulting Services",
            quantity = 10,
            unitCode = "H87",
            unitPrice = 500.00,
            invoiceLineTaxes = new[] {
                new { taxType = "01", taxRate = 8 }
            }
        }
    }
};

response = await client.PostAsJsonAsync($"{API_URL}/invoices", invoiceData);
var invoice = await response.Content.ReadFromJsonAsync<JsonElement>();
var invoiceId = invoice.GetProperty("data").GetProperty("id").GetString();
var payable = invoice.GetProperty("data").GetProperty("payableAmount").GetString();
Console.WriteLine($"Created invoice: {invoiceId} (RM {payable})\n");

// Step 3: Validate
Console.WriteLine("Step 3: Validating invoice...");
response = await client.PostAsync($"{API_URL}/documents/{invoiceId}/validate", null);
var validation = await response.Content.ReadFromJsonAsync<JsonElement>();
Console.WriteLine($"Validation: {validation.GetProperty("data").GetProperty("status")}\n");

// Step 4: Submit to LHDN
Console.WriteLine("Step 4: Submitting to LHDN...");
response = await client.PostAsync($"{API_URL}/documents/{invoiceId}/submit", null);
var submission = await response.Content.ReadFromJsonAsync<JsonElement>();
var documentUuid = submission.GetProperty("data").GetProperty("document_uuid").GetString();
Console.WriteLine($"Submitted! LHDN UUID: {documentUuid}\n");

// Step 5: Check Status
Console.WriteLine("Step 5: Checking LHDN status...");
var status = "Submitted";
var attempts = 0;

while (status == "Submitted" && attempts < 10)
{
    await Task.Delay(2000);
    attempts++;

    response = await client.GetAsync($"{API_URL}/documents/{invoiceId}/status");
    var statusCheck = await response.Content.ReadFromJsonAsync<JsonElement>();
    status = statusCheck.GetProperty("data").GetProperty("status").GetString() ?? "Unknown";
    Console.WriteLine($"Attempt {attempts}: {status}");
}
Console.WriteLine();

// Step 6: Get QR Code
if (status == "Valid")
{
    Console.WriteLine("Step 6: Getting QR code...");
    response = await client.GetAsync($"{API_URL}/documents/{invoiceId}/qr");
    var qr = await response.Content.ReadFromJsonAsync<JsonElement>();
    Console.WriteLine($"Verification URL: {qr.GetProperty("data").GetProperty("verification_url")}");

    var qrData = qr.GetProperty("data").GetProperty("qr_code").GetString()!
        .Replace("data:image/png;base64,", "");
    await File.WriteAllBytesAsync("invoice-qr.png", Convert.FromBase64String(qrData));
    Console.WriteLine("QR code saved to: invoice-qr.png");
}

Console.WriteLine("\n=== Complete! ===");

Expected Output

=== InvoisX Complete Flow ===

Step 1: Creating buyer...
Created buyer: 9e1a2b3c-4d5e-6f7a-8b9c-0d1e2f3a4b5c

Step 2: Creating invoice...
Created invoice: a1b2c3d4-e5f6-7890-abcd-ef1234567890 (RM 5400.00)

Step 3: Validating invoice...
Validation: ready

Step 4: Submitting to LHDN...
Submitted! LHDN UUID: QZSABHBPPZH51WM6G06KSSBK10

Step 5: Checking LHDN status...
Attempt 1: Submitted
Attempt 2: Valid

Step 6: Getting QR code...
Verification URL: https://myinvois.hasil.gov.my/...
QR code saved to: invoice-qr.png

=== Complete! ===

Next Steps

InvoisX - Malaysia's Leading e-Invoice Platform