How to Integrate E-Invoice API Using PHP?

ewaybill
E-Invoice

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.

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.

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.

Leave your thought here

Your email address will not be published. Required fields are marked *