How to Integrate E-Invoice API Using PHP?
PHP powers a large share of India’s billing platforms, ERP systems, and accounting applications. If your PHP application generates B2B invoices and your business has crossed the prescribed GST turnover threshold, every one of those invoices must be registered with the Invoice Registration Portal to receive an IRN. Without the IRN and the signed QR code, the buyer cannot claim ITC against the invoice.
The E-Invoice API handles the entire registration flow payload validation, IRP submission, IRN generation, digital signing, and QR code delivery in a single call. Here is exactly how to build that integration in PHP.
What You Need Before Starting
Install Guzzle HTTP client and phpdotenv via Composer:
composer require guzzlehttp/guzzle
composer require vlucas/phpdotenv
Create a .env file:
PERIONE_API_KEY=your_api_key_here
PERIONE_CLIENT_SECRET=your_client_secret_here
GSTIN=29DDDDD3333D1Z8
PERIONE_BASE_URL=https://api.perionetech.in/v1
You also need a PeriOne developer account with e-Invoice API access enabled and your GSTIN verified on the platform.
Step 1 — Authenticate and Cache the Session Token
The authentication endpoint is:
POST /einvoice/authenticate
Required request headers:
Content-Type: application/json
x-api-key: your_api_key_here
Request body:
{
“gstin”: “29DDDDD3333D1Z8”,
“app_key”: “your_client_secret_here”
}
Successful response:
{
“status”: “success”,
“data”: {
“auth_token”: “eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9…”,
“token_expiry”: “2024-11-15T20:00:00Z”,
“gstin”: “29DDDDD3333D1Z8”
}
}
Failed response:
{
“status”: “error”,
“error_code”: “AUTH001”,
“message”: “Invalid API key. Verify credentials in PeriOne developer console.”
}
In PHP, the best approach is a class with static token properties. Store the auth_token and its expiry timestamp as static variables. Every time a token is needed, check whether the cached value is still valid with at least a five-minute buffer. If valid, return it immediately. If not, call the API, update the static values, and return the new token.
Step 2 — Required Headers for Every E-Invoice API Call
Every e-Invoice request after authentication must carry these four headers:
Content-Type: application/json
x-api-key: your_permanent_api_key
Authorization: Bearer eyJhbGciOiJSUzI1NiI…
gstin: 29DDDDD3333D1Z8
All four are mandatory on every request. A missing or expired Authorization header returns 401. A missing gstin header causes the IRP to reject the request because it cannot identify which taxpayer is authorising the operation.
Step 3 — Build and Submit the IRN Generation Payload
The IRN generation endpoint is:
POST /einvoice/generate
The request body follows the GSTN e-Invoice schema with five sections —
transaction details, document details, seller details, buyer details, item list, and value totals:
{
“Version”: “1.1”,
“TranDtls”: {
“TaxSch”: “GST”,
“SupTyp”: “B2B”,
“RegRev”: “N”,
“EcmGstin”: null
},
“DocDtls”: {
“Typ”: “INV”,
“No”: “INV-2024-00451”,
“Dt”: “15/11/2024”
},
“SellerDtls”: {
“Gstin”: “29DDDDD3333D1Z8”,
“LglNm”: “ABC Manufacturing Pvt Ltd”,
“TrdNm”: “ABC Manufacturing”,
“Addr1”: “Plot 23, KIADB Industrial Area”,
“Addr2”: “Phase 1”,
“Loc”: “Bangalore”,
“Pin”: 560058,
“Stcd”: “29”,
“Ph”: “9876543210”,
“Em”: “accounts@abcmfg.com”
},
“BuyerDtls”: {
“Gstin”: “27BBBBB1111B1Z6”,
“LglNm”: “XYZ Traders Pvt Ltd”,
“TrdNm”: “XYZ Traders”,
“Pos”: “27”,
“Addr1”: “Gala 5, Kurla Industrial Estate”,
“Addr2”: “”,
“Loc”: “Mumbai”,
“Pin”: 400070,
“Stcd”: “27”
},
“ItemList”: [
{
“SlNo”: “1”,
“PrdDesc”: “Industrial Motor 5HP”,
“IsServc”: “N”,
“HsnCd”: “85011020”,
“Qty”: 10.00,
“Unit”: “NOS”,
“UnitPrice”: 8500.00,
“TotAmt”: 85000.00,
“Discount”: 0,
“AssAmt”: 85000.00,
“GstRt”: 18.00,
“IgstAmt”: 15300.00,
“CgstAmt”: 0,
“SgstAmt”: 0,
“TotItemVal”: 100300.00
}
],
“ValDtls”: {
“AssVal”: 85000.00,
“CgstVal”: 0,
“SgstVal”: 0,
“IgstVal”: 15300.00,
“CesVal”: 0,
“RndOffAmt”: 0,
“TotInvVal”: 100300.00
}
}
Three rules that catch developers off guard. The DocDtls.No field only accepts alphanumeric characters, forward slashes, and hyphens any bracket, comma, or space causes error 2207. Unit codes must match the GSTN master: NOS not PCS, KGS not KG. The ValDtls section must equal the exact arithmetic sum of the ItemList tax amounts even a Rs. 0.01 difference causes error 2205.
Step 4 — Parse the IRN Response and Save to Database
A successful IRN generation returns:
{
“status”: “success”,
“data”: {
“Irn”: “a5c12b3d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b”,
“AckNo”: 112024456789012,
“AckDt”: “2024-11-15 10:30:25”,
“SignedInvoice”: “eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9…”,
“SignedQRCode”: “eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9…”,
“Status”: “ACT”
}
}
Save all fields to your database immediately. The Irn is the 64-character Invoice Reference Number. The Signed Invoice JSON is your legal proof of IRP registration. The Signed QR Code is base64-encoded decode it and render it as a QR code image embedded in your invoice PDF at a minimum size of 2×2 inches.
Step 5 — Cancel an IRN When Needed
If an invoice needs to be cancelled within 24 hours of generation, use:
POST /einvoice/cancel
Request body:
{
“Irn”: “a5c12b3d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b”,
“CnlRsn”: 2,
“CnlRem”: “Wrong buyer GSTIN entered”
}
Cancellation reason codes: 1 for duplicate, 2 for data entry error, 3 for order cancelled, 4 for other.
Successful response:
{
“status”: “success”,
“data”: {
“Irn”: “a5c12b3d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b”,
“CancelDate”: “2024-11-15 11:45:00”
}
}
Update the IRN status to CANCELLED in your database immediately after this response. After 24 hours, cancellation through the API is no longer possible.
Common E-Invoice API Errors in PHP
Error 2150 is the most common production error — duplicate IRN. The same invoice was already registered on the IRP. Before calling generate, always check your database for an existing active IRN. If not in your DB, call GET /einvoice/irn with the invoice details to retrieve the existing IRN.
Error 2183 fires when the buyer GSTIN is invalid or inactive. Validate GSTINs using PeriOne’s GSTIN Validation API before generating invoices, not after receiving this error.
Error 2202 fires for an invalid HSN code. Validate HSN codes at product master creation catching them at invoice generation time is too late.
Error 2205 fires when ValDtls totals do not match the ItemList sum. Always calculate header totals by aggregating from line items in your integration code.
Error 2207 fires for invalid invoice number characters. Strip all characters except alphanumeric, forward slash, and hyphen before submission.
The Complete Integration Flow
Your PHP Application
|
|— POST /einvoice/authenticate
| Headers: Content-Type, x-api-key
| Body: { gstin, app_key }
| |
| Returns: { auth_token, token_expiry }
| Cache in static class property
|
|— Build e-Invoice JSON payload
| Map invoice DB fields to GSTN schema
| Validate GSTIN, HSN codes, tax totals
|
|— POST /einvoice/generate
| Headers: x-api-key, Authorization, gstin
| Body: Full e-Invoice JSON
| |
| PeriOne –> IRP Government Portal
| Validates –> Signs –> Returns IRN
| |
| Returns: { Irn, AckNo, SignedQRCode }
|
|— Save IRN + AckNo + SignedInvoice to database
|— Decode SignedQRCode –> Render in invoice PDF
|
|— On error: Classify –> Retry or Alert
|— On cancel needed: POST /einvoice/cancel
Integrating E-Invoice API in PHP follows a clean, structured pattern. Build a dedicated authentication class that handles token caching. Build a payload mapper that converts your database fields to the GSTN schema. Handle errors by classifying them retriable versus data errors and route each to the right action. Write the IRN and QR code back to your database immediately after every successful call. These steps, done correctly, produce a production-grade integration that scales to any invoice volume.
FAQ’s
How do I prevent token expiry errors in production?
Store the auth_token and token_expiry from the authentication response in module-level variables. Before every API call, calculate whether the current time is within five minutes of expiry. If yes, call authenticate, update the stored values, and proceed. If no, use the cached token directly.
Can I generate E-Way Bills in bulk using Node.js?
Yes. PeriOne’s E-Way Bill API supports a bulk generation endpoint that accepts an array of EWB payloads in one call. Each invoice in the batch receives an independent success or failure response, so partial batch success is handled cleanly.
What is the validity period of an E-Way Bill?
Validity is distance-based — one day per 200 km for regular vehicles and one day per 20 km for over-dimensional cargo. The API response always includes the exact ewbValidTill timestamp.
Related Posts
Complete Guide to e-Invoice API Integration in India
Categories
Latest Posts