Skip to content

QR Codes & PDFs

Retrieve verification QR codes and PDF documents for LHDN-validated invoices.

Setup

Before using the examples below, set up your HTTP client:

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

async function api(method, endpoint, data = null) {
  const response = await fetch(`${API_URL}${endpoint}`, {
    method,
    headers: {
      'Authorization': `Bearer ${API_TOKEN}`,
      'Accept': 'application/json',
      'Content-Type': 'application/json',
    },
    body: data ? JSON.stringify(data) : null,
  });
  return response.json();
}
python
import requests

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

def api(method, endpoint, data=None):
    response = requests.request(
        method,
        f'{API_URL}{endpoint}',
        headers={
            'Authorization': f'Bearer {API_TOKEN}',
            'Accept': 'application/json',
        },
        json=data
    )
    return response.json()
php
use Illuminate\Support\Facades\Http;

$api = Http::withToken('your-api-token')
    ->accept('application/json')
    ->baseUrl('https://invoisx.com/api/v1');
php
use GuzzleHttp\Client;

$client = new Client([
    'base_uri' => 'https://invoisx.com/api/v1/',
    'headers' => [
        'Authorization' => 'Bearer your-api-token',
        'Accept' => 'application/json',
        'Content-Type' => 'application/json',
    ],
]);
java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

HttpClient client = HttpClient.newHttpClient();
String API_URL = "https://invoisx.com/api/v1";
String API_TOKEN = "your-api-token";
csharp
using System.Net.Http;
using System.Net.Http.Json;
using System.Text.Json;

var client = new HttpClient {
    BaseAddress = new Uri("https://invoisx.com/api/v1")
};
client.DefaultRequestHeaders.Add("Authorization", "Bearer your-api-token");
client.DefaultRequestHeaders.Add("Accept", "application/json");

Overview

Once a document is Valid, you can:

  • Generate a QR code for customer verification
  • Retrieve a PDF version of the document

Both link to LHDN's official verification portal.

Getting the QR Code

JSON Response (Default)

Returns base64-encoded QR code and verification URL:

javascript
const qr = await api('GET', `/documents/${documentId}/qr`);

console.log(`Verification URL: ${qr.data.verification_url}`);

// Save QR code to file
const qrData = qr.data.qr_code.replace('data:image/png;base64,', '');
fs.writeFileSync('invoice-qr.png', Buffer.from(qrData, 'base64'));
python
import base64

qr = api('GET', f'/documents/{document_id}/qr')

print(f"Verification URL: {qr['data']['verification_url']}")

# Save QR code to file
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))
php
$response = $api->get("/documents/$documentId/qr");
$result = $response->json('data');

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

// Save QR code to file
$qrData = str_replace('data:image/png;base64,', '', $result['qr_code']);
file_put_contents('invoice-qr.png', base64_decode($qrData));
php
$response = $client->get("documents/$documentId/qr");
$result = json_decode($response->getBody(), true)['data'];

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

// Save QR code to file
$qrData = str_replace('data:image/png;base64,', '', $result['qr_code']);
file_put_contents('invoice-qr.png', base64_decode($qrData));
java
var request = HttpRequest.newBuilder()
    .uri(URI.create(API_URL + "/documents/" + documentId + "/qr"))
    .header("Authorization", "Bearer " + API_TOKEN)
    .GET()
    .build();

var response = client.send(request, HttpResponse.BodyHandlers.ofString());
// Parse JSON to get verification_url and qr_code
// Decode base64 qr_code and save to file
System.out.println("Response: " + response.body());
csharp
var response = await client.GetAsync($"/documents/{documentId}/qr");
var json = await response.Content.ReadFromJsonAsync<JsonElement>();
var data = json.GetProperty("data");

Console.WriteLine($"Verification URL: {data.GetProperty("verification_url").GetString()}");

// Save QR code to file
var qrCode = data.GetProperty("qr_code").GetString();
var qrData = qrCode.Replace("data:image/png;base64,", "");
await File.WriteAllBytesAsync("invoice-qr.png", Convert.FromBase64String(qrData));

Response

json
{
  "success": true,
  "data": {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "qr_code": "data:image/png;base64,iVBORw0KGgo...",
    "verification_url": "https://myinvois.hasil.gov.my/..."
  }
}

Direct Image Response

Get the QR code as a ready-to-use image file:

javascript
// Get as PNG
const response = await fetch(`${API_URL}/documents/${documentId}/qr`, {
  headers: {
    'Authorization': `Bearer ${API_TOKEN}`,
    'Accept': 'image/png'  // Request image directly
  }
});

const buffer = await response.arrayBuffer();
fs.writeFileSync('invoice-qr.png', Buffer.from(buffer));
python
# Get as PNG
response = requests.get(
    f'{API_URL}/documents/{document_id}/qr',
    headers={
        'Authorization': f'Bearer {API_TOKEN}',
        'Accept': 'image/png'  # Request image directly
    }
)

with open('invoice-qr.png', 'wb') as f:
    f.write(response.content)
php
// Get as PNG
$response = Http::withToken($apiToken)
    ->accept('image/png')  // Request image directly
    ->get("$apiUrl/documents/$documentId/qr");

file_put_contents('invoice-qr.png', $response->body());
php
// Get as PNG
$response = $client->get("documents/$documentId/qr", [
    'headers' => ['Accept' => 'image/png']  // Request image directly
]);

file_put_contents('invoice-qr.png', $response->getBody()->getContents());
java
// Get as PNG
var request = HttpRequest.newBuilder()
    .uri(URI.create(API_URL + "/documents/" + documentId + "/qr"))
    .header("Authorization", "Bearer " + API_TOKEN)
    .header("Accept", "image/png")  // Request image directly
    .GET()
    .build();

var response = client.send(request, HttpResponse.BodyHandlers.ofByteArray());
Files.write(Path.of("invoice-qr.png"), response.body());
csharp
// Get as PNG
using var request = new HttpRequestMessage(HttpMethod.Get, $"/documents/{documentId}/qr");
request.Headers.Accept.Clear();
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("image/png"));

var response = await client.SendAsync(request);
var bytes = await response.Content.ReadAsByteArrayAsync();
await File.WriteAllBytesAsync("invoice-qr.png", bytes);

Supported Image Formats

Accept HeaderFormat
image/pngPNG image
image/jpegJPEG image
application/jsonJSON with base64 (default)

Getting the PDF

Retrieve a PDF version of the document:

javascript
const response = await fetch(`${API_URL}/documents/${documentId}/pdf`, {
  headers: {
    'Authorization': `Bearer ${API_TOKEN}`,
    'Accept': 'application/pdf'
  }
});

const buffer = await response.arrayBuffer();
fs.writeFileSync('invoice.pdf', Buffer.from(buffer));
console.log('PDF saved to: invoice.pdf');
python
response = requests.get(
    f'{API_URL}/documents/{document_id}/pdf',
    headers={
        'Authorization': f'Bearer {API_TOKEN}',
        'Accept': 'application/pdf'
    }
)

with open('invoice.pdf', 'wb') as f:
    f.write(response.content)
print('PDF saved to: invoice.pdf')
php
$response = Http::withToken($apiToken)
    ->accept('application/pdf')
    ->get("$apiUrl/documents/$documentId/pdf");

if ($response->successful()) {
    file_put_contents('invoice.pdf', $response->body());
    echo "PDF saved to: invoice.pdf\n";
}
php
$response = $client->get("documents/$documentId/pdf", [
    'headers' => ['Accept' => 'application/pdf']
]);

file_put_contents('invoice.pdf', $response->getBody()->getContents());
echo "PDF saved to: invoice.pdf\n";
java
var request = HttpRequest.newBuilder()
    .uri(URI.create(API_URL + "/documents/" + documentId + "/pdf"))
    .header("Authorization", "Bearer " + API_TOKEN)
    .header("Accept", "application/pdf")
    .GET()
    .build();

var response = client.send(request, HttpResponse.BodyHandlers.ofByteArray());
Files.write(Path.of("invoice.pdf"), response.body());
System.out.println("PDF saved to: invoice.pdf");
csharp
using var request = new HttpRequestMessage(HttpMethod.Get, $"/documents/{documentId}/pdf");
request.Headers.Accept.Clear();
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/pdf"));

var response = await client.SendAsync(request);
var bytes = await response.Content.ReadAsByteArrayAsync();
await File.WriteAllBytesAsync("invoice.pdf", bytes);
Console.WriteLine("PDF saved to: invoice.pdf");

Using QR Codes in Your Application

HTML Embed (Base64)

html
<img src="{{ qr_code }}" alt="LHDN Verification QR Code" />
html
<div class="verification">
  <img src="{{ qr_code }}" alt="Scan to verify" />
  <p>Scan to verify on LHDN MyInvois</p>
  <a href="{{ verification_url }}">Or click here to verify</a>
</div>
html
<div class="invoice-footer">
  <div class="qr-section">
    <img src="{{ qr_code }}" width="100" height="100" />
    <small>Scan to verify this e-invoice on LHDN MyInvois</small>
  </div>
  <div class="lhdn-info">
    <p>Document UUID: {{ document_uuid }}</p>
    <p>Validated: {{ validated_at }}</p>
  </div>
</div>

Error Handling

Document Not Valid

QR codes are only available for Valid documents:

json
{
  "success": false,
  "message": "QR code is only available for validated documents",
  "error_code": "DOCUMENT_NOT_VALID"
}

Solution: Wait for document to be validated by LHDN.

Checking Before Request

javascript
// Check status first
const status = await api('GET', `/documents/${documentId}/status`);

if (status.data.status === 'Valid') {
  const qr = await api('GET', `/documents/${documentId}/qr`);
  // Use QR code
} else {
  console.log(`Document status: ${status.data.status}`);
}
python
# Check status first
status = api('GET', f'/documents/{document_id}/status')

if status['data']['status'] == 'Valid':
    qr = api('GET', f'/documents/{document_id}/qr')
    # Use QR code
else:
    print(f"Document status: {status['data']['status']}")
php
// Check status first
$status = $api->get("/documents/$documentId/status")->json('data');

if ($status['status'] === 'Valid') {
    $qr = $api->get("/documents/$documentId/qr")->json('data');
    // Use QR code
} else {
    echo "Document status: {$status['status']}\n";
}
php
// Check status first
$response = $client->get("documents/$documentId/status");
$status = json_decode($response->getBody(), true)['data'];

if ($status['status'] === 'Valid') {
    $response = $client->get("documents/$documentId/qr");
    $qr = json_decode($response->getBody(), true)['data'];
    // Use QR code
} else {
    echo "Document status: {$status['status']}\n";
}
java
// Check status first
var statusRequest = HttpRequest.newBuilder()
    .uri(URI.create(API_URL + "/documents/" + documentId + "/status"))
    .header("Authorization", "Bearer " + API_TOKEN)
    .GET()
    .build();

var statusResponse = client.send(statusRequest, HttpResponse.BodyHandlers.ofString());
// Parse JSON to check status

// If Valid, get QR code
var qrRequest = HttpRequest.newBuilder()
    .uri(URI.create(API_URL + "/documents/" + documentId + "/qr"))
    .header("Authorization", "Bearer " + API_TOKEN)
    .GET()
    .build();

var qrResponse = client.send(qrRequest, HttpResponse.BodyHandlers.ofString());
// Use QR code
csharp
// Check status first
var statusResponse = await client.GetAsync($"/documents/{documentId}/status");
var statusJson = await statusResponse.Content.ReadFromJsonAsync<JsonElement>();
var status = statusJson.GetProperty("data").GetProperty("status").GetString();

if (status == "Valid") {
    var qrResponse = await client.GetAsync($"/documents/{documentId}/qr");
    var qrJson = await qrResponse.Content.ReadFromJsonAsync<JsonElement>();
    var qrData = qrJson.GetProperty("data");
    // Use QR code
} else {
    Console.WriteLine($"Document status: {status}");
}

Complete Example

javascript
async function getInvoiceWithQR(documentId) {
  // 1. Check status
  const status = await api('GET', `/documents/${documentId}/status`);

  if (status.data.status !== 'Valid') {
    throw new Error(`Document not valid: ${status.data.status}`);
  }

  // 2. Get document details
  const doc = await api('GET', `/invoices/${documentId}`);

  // 3. Get QR code
  const qr = await api('GET', `/documents/${documentId}/qr`);

  return {
    invoice: doc.data,
    qr_code: qr.data.qr_code,
    verification_url: qr.data.verification_url,
    document_uuid: status.data.document_uuid,
    validated_at: status.data.validated_at
  };
}

const result = await getInvoiceWithQR(documentId);
console.log('Invoice:', result.invoice.invoiceSerialNumber);
console.log('Verification URL:', result.verification_url);
python
def get_invoice_with_qr(document_id):
    # 1. Check status
    status = api('GET', f'/documents/{document_id}/status')

    if status['data']['status'] != 'Valid':
        raise Exception(f"Document not valid: {status['data']['status']}")

    # 2. Get document details
    doc = api('GET', f'/invoices/{document_id}')

    # 3. Get QR code
    qr = api('GET', f'/documents/{document_id}/qr')

    return {
        'invoice': doc['data'],
        'qr_code': qr['data']['qr_code'],
        'verification_url': qr['data']['verification_url'],
        'document_uuid': status['data']['document_uuid'],
        'validated_at': status['data']['validated_at']
    }

result = get_invoice_with_qr(document_id)
print(f"Invoice: {result['invoice']['invoiceSerialNumber']}")
print(f"Verification URL: {result['verification_url']}")
php
function getInvoiceWithQR($api, $documentId) {
    // 1. Check status
    $status = $api->get("/documents/$documentId/status")->json('data');

    if ($status['status'] !== 'Valid') {
        throw new Exception("Document not valid: {$status['status']}");
    }

    // 2. Get document details
    $doc = $api->get("/invoices/$documentId")->json('data');

    // 3. Get QR code
    $qr = $api->get("/documents/$documentId/qr")->json('data');

    return [
        'invoice' => $doc,
        'qr_code' => $qr['qr_code'],
        'verification_url' => $qr['verification_url'],
        'document_uuid' => $status['document_uuid'],
        'validated_at' => $status['validated_at']
    ];
}

$result = getInvoiceWithQR($api, $documentId);
echo "Invoice: {$result['invoice']['invoiceSerialNumber']}\n";
echo "Verification URL: {$result['verification_url']}\n";
php
function getInvoiceWithQR($client, $documentId) {
    // 1. Check status
    $response = $client->get("documents/$documentId/status");
    $status = json_decode($response->getBody(), true)['data'];

    if ($status['status'] !== 'Valid') {
        throw new Exception("Document not valid: {$status['status']}");
    }

    // 2. Get document details
    $response = $client->get("invoices/$documentId");
    $doc = json_decode($response->getBody(), true)['data'];

    // 3. Get QR code
    $response = $client->get("documents/$documentId/qr");
    $qr = json_decode($response->getBody(), true)['data'];

    return [
        'invoice' => $doc,
        'qr_code' => $qr['qr_code'],
        'verification_url' => $qr['verification_url'],
        'document_uuid' => $status['document_uuid'],
        'validated_at' => $status['validated_at']
    ];
}

$result = getInvoiceWithQR($client, $documentId);
echo "Invoice: {$result['invoice']['invoiceSerialNumber']}\n";
echo "Verification URL: {$result['verification_url']}\n";
java
public Map<String, Object> getInvoiceWithQR(String documentId) throws Exception {
    // 1. Check status
    var statusRequest = HttpRequest.newBuilder()
        .uri(URI.create(API_URL + "/documents/" + documentId + "/status"))
        .header("Authorization", "Bearer " + API_TOKEN)
        .GET()
        .build();
    var statusResponse = client.send(statusRequest, HttpResponse.BodyHandlers.ofString());
    // Parse status from JSON

    // 2. Get document details
    var docRequest = HttpRequest.newBuilder()
        .uri(URI.create(API_URL + "/invoices/" + documentId))
        .header("Authorization", "Bearer " + API_TOKEN)
        .GET()
        .build();
    var docResponse = client.send(docRequest, HttpResponse.BodyHandlers.ofString());

    // 3. Get QR code
    var qrRequest = HttpRequest.newBuilder()
        .uri(URI.create(API_URL + "/documents/" + documentId + "/qr"))
        .header("Authorization", "Bearer " + API_TOKEN)
        .GET()
        .build();
    var qrResponse = client.send(qrRequest, HttpResponse.BodyHandlers.ofString());

    // Return combined result
    return Map.of(
        "invoice", parseInvoice(docResponse.body()),
        "qr_code", parseQrCode(qrResponse.body()),
        "verification_url", parseVerificationUrl(qrResponse.body())
    );
}

var result = getInvoiceWithQR(documentId);
System.out.println("Invoice: " + result.get("invoice"));
System.out.println("Verification URL: " + result.get("verification_url"));
csharp
async Task<Dictionary<string, object>> GetInvoiceWithQR(string documentId) {
    // 1. Check status
    var statusResponse = await client.GetAsync($"/documents/{documentId}/status");
    var statusJson = await statusResponse.Content.ReadFromJsonAsync<JsonElement>();
    var status = statusJson.GetProperty("data");

    if (status.GetProperty("status").GetString() != "Valid") {
        throw new Exception($"Document not valid: {status.GetProperty("status").GetString()}");
    }

    // 2. Get document details
    var docResponse = await client.GetAsync($"/invoices/{documentId}");
    var docJson = await docResponse.Content.ReadFromJsonAsync<JsonElement>();
    var doc = docJson.GetProperty("data");

    // 3. Get QR code
    var qrResponse = await client.GetAsync($"/documents/{documentId}/qr");
    var qrJson = await qrResponse.Content.ReadFromJsonAsync<JsonElement>();
    var qr = qrJson.GetProperty("data");

    return new Dictionary<string, object> {
        ["invoice"] = doc,
        ["qr_code"] = qr.GetProperty("qr_code").GetString(),
        ["verification_url"] = qr.GetProperty("verification_url").GetString(),
        ["document_uuid"] = status.GetProperty("document_uuid").GetString(),
        ["validated_at"] = status.GetProperty("validated_at").GetString()
    };
}

var result = await GetInvoiceWithQR(documentId);
Console.WriteLine($"Invoice: {((JsonElement)result["invoice"]).GetProperty("invoiceSerialNumber").GetString()}");
Console.WriteLine($"Verification URL: {result["verification_url"]}");

Next Steps

InvoisX - Malaysia's Leading e-Invoice Platform