> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pdf.co/llms.txt
> Use this file to discover all available pages before exploring further.

# AI Invoice Parser

> Process invoices faster than ever by extracting data and structuring it automatically with our advanced AI. Get quick and accurate data from any invoice, no matter the layout.

## `POST /ai-invoice-parser`

The AI Invoice parser automatically detects invoice layouts without the manual effort previously required to supply document parsing templates for reference.

<Warning>
  **Important**

  * **Only invoices will be parsed**. For all other documents, please use our existing [**Document Parser**](/api-reference/documentparser/parser).
  * To ensure accurate processing, each invoice must be clearly separated. **If an invoice contains multiple pages, we recommend splitting it** into individual PDFs using the [PDF Split API](/api-reference/pdf-split/by-pages).
  * While AI Invoice Parser supports multi-page invoices, **the total page count for a single PDF must not exceed 100 pages**. Submitting large PDFs containing multiple invoices is not recommended.
  * To retrieve results, you must poll the [Background Job Check](/api-reference/job-check) endpoint using the `jobId` returned in the initial response. Once the job status is marked as `success`, the output file will be available at the provided URL.
</Warning>

<Note>
  This method extracts data from your PDF invoices and returns a [well-structured JSON format](/api-reference/ai-invoice-parser/#example-response) for your use.
</Note>

## Attributes

<Note>
  Attributes are case-sensitive and should be inside JSON for POST request. for example: `{ "url": "https://example.com/file1.pdf" }`
</Note>

| Attribute                 | Type   | Required | Default | Description                                                                                                                                                                                                                |
| ------------------------- | ------ | -------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `url`                     | string | *Yes*    | -       | URL to the source file [`url attribute`](/api-reference/url-input-and-request-limits#supported-file-sources)                                                                                                               |
| `customField`             | string | *No*     | -       | JSON string containing [custom field](/api-reference/ai-invoice-parser/#custom-fields) names to extract. Use `camelCase` for field names (e.g., `storeNumber`, `deliveryDate`). Multiple fields should be comma-separated. |
| `lineItemStructure`       | object | *No*     | -       | Defines a custom structure for line items in the response. See [Line Item Structure](/api-reference/ai-invoice-parser/#line-item-structure) for more information.                                                          |
| `callback`                | string | *No*     | -       | The callback URL (or Webhook) used to receive the POST data. see [Webhooks & Callbacks](/api-reference/webhooks). This is only applicable when `async` is set to `true`.                                                   |
| `profiles`                | object | *No*     | -       | See [Profiles](/api-reference/profiles) for more information.                                                                                                                                                              |
| `DataEncryptionAlgorithm` | string | *No*     | -       | Controls the encryption algorithm used for data encryption. See [User-Controlled Encryption](/knowledgebase/user-controlled-encryption) for more information. The available algorithms are: `AES128`, `AES192`, `AES256`.  |
| `DataEncryptionKey`       | string | *No*     | -       | Controls the encryption key used for data encryption. See [User-Controlled Encryption](/knowledgebase/user-controlled-encryption) for more information.                                                                    |
| `DataEncryptionIV`        | string | *No*     | -       | Controls the encryption IV used for data encryption. See [User-Controlled Encryption](/knowledgebase/user-controlled-encryption) for more information.                                                                     |
| `DataDecryptionAlgorithm` | string | *No*     | -       | Controls the decryption algorithm used for data decryption. See [User-Controlled Encryption](/knowledgebase/user-controlled-encryption) for more information. The available algorithms are: `AES128`, `AES192`, `AES256`.  |
| `DataDecryptionKey`       | string | *No*     | -       | Controls the decryption key used for data decryption. See [User-Controlled Encryption](/knowledgebase/user-controlled-encryption) for more information.                                                                    |
| `DataDecryptionIV`        | string | *No*     | -       | Controls the decryption IV used for data decryption. See [User-Controlled Encryption](/knowledgebase/user-controlled-encryption) for more information.                                                                     |

## Custom Fields

AI Invoice Parser with custom fields support automatically detects invoice layouts and extracts both standard schema data and user-specified custom fields without requiring manual templates.

The `customField` parameter allows you to specify additional fields to extract beyond the standard schema. Some examples include:

* `storeNumber` - Store or branch identifier
* `deliveryDate` - Expected delivery date
* `financialCharges` - Additional financial charges
* `lineTotal` - Total amount for line items
* `purchaseOrderRef` - Purchase order reference number
* `customerReference` - Customer reference number
* `departmentCode` - Department or cost center code

<Note>
  If a custom field returns an empty value, please [contact our support team](https://pdf.co/support/request?subject=ai-invoice-parser%20-%20custom%20fields) to help improve the extraction accuracy.
</Note>

## Line Item Structure

The `lineItemStructure` attribute lets you define a custom schema for line items. Each key is a field name you choose (in `camelCase`) and each value is the expected data type — either `"string"` or `"number"`.

When provided, every object inside the `lineItems` array will contain exactly the fields you specified. If a value cannot be extracted from the invoice, the field will still be present with an empty or default value instead of being omitted.

### Example

```json theme={null}
{
  "url": "https://pdfco-test-files.s3.us-west-2.amazonaws.com/document-parser/sample-invoice.pdf",
  "async": true,
  "lineItemStructure": {
    "description": "string",
    "quantity": "number",
    "unitPrice": "number",
    "totalPrice": "number"
  }
}
```

With the structure above, every line item in the response will include all four fields:

```json theme={null}
"lineItems": [
  [
    {
      "description": "Item 1",
      "quantity": 2,
      "unitPrice": 9.95,
      "totalPrice": 19.90
    },
    {
      "description": "Item 2",
      "quantity": 5,
      "unitPrice": 20.00,
      "totalPrice": 100.00
    }
  ]
]
```

<Note>
  Use `camelCase` for field names (e.g., `unitPrice`, `totalPrice`). The field names you define will be used as-is in the response, giving you full control over the output keys.
</Note>

## Query parameters

*No query parameters accepted.*

## Responses

| Parameter          | Type    | Description                                                                            |
| ------------------ | ------- | -------------------------------------------------------------------------------------- |
| `status`           | string  | Status of the API response. The statuses are: `success`, `error`.                      |
| `message`          | string  | Descriptive message for the response status.                                           |
| `pageCount`        | integer | Number of pages processed or returned.                                                 |
| `body`             | object  | Contains the invoice data. See [Invoice Schema](#invoice-schema) for more information. |
| `jobId`            | string  | Unique identifier for the background job.                                              |
| `credits`          | integer | Credits used for this operation.                                                       |
| `remainingCredits` | integer | Credits left after this job execution.                                                 |
| `duration`         | integer | Time taken to complete the request, in milliseconds.                                   |

### Invoice Schema

The `body` object contains all the metadata needed to understand your invoice content and includes the following attributes:

```json theme={null}
"body": {
  "vendor": { .... },
  "customer": { .... },
  "invoice": { .... },
  "paymentDetails": { .... },
  "others": { .... },
  "lineItems": { .... }
}
```

#### Sections

* [vendor](#vendor-object)
* [customer](#customer-object)
* [invoice](#invoice-object)
* [paymentDetails](#paymentdetails-object)
* [others](#others-object)
* [lineItems](#lineitems-object)

***

### The `vendor` Object

An `object` containing vendor details.

| Attribute            | Type   | Description                                                                         |
| -------------------- | ------ | ----------------------------------------------------------------------------------- |
| `name`               | string | Name of the vendor                                                                  |
| `address`            | object | Vendor's address details. See [address object](#address-object)                     |
| `contactInformation` | object | Vendor contact details. See [contactInformation object](#contactinformation-object) |
| `entityId`           | object | Vendor's entity ID (e.g., EIN, ABN, VAT, GST, etc.)                                 |

***

### The `customer` Object

An `object` containing customer details.

| Attribute | Type   | Description                                              |
| --------- | ------ | -------------------------------------------------------- |
| `billTo`  | object | Billing details. See [customer.billTo](#customerbillto)  |
| `shipTo`  | object | Shipping details. See [customer.shipTo](#customershipto) |

### `customer.billTo`

| Attribute            | Type   | Description                                                 |
| -------------------- | ------ | ----------------------------------------------------------- |
| `name`               | string | Customer name                                               |
| `address`            | object | See [address object](#address-object)                       |
| `contactInformation` | object | See [contactInformation object](#contactinformation-object) |
| `entityId`           | string | Customer's entity ID (e.g., EIN, ABN, VAT, GST, etc.)       |

### `customer.shipTo`

| Attribute | Type   | Description                           |
| --------- | ------ | ------------------------------------- |
| `name`    | string | Customer name                         |
| `address` | object | See [address object](#address-object) |

***

### The `invoice` Object

An `object` containing the invoice details.

| Attribute     | Type   | Description           |
| ------------- | ------ | --------------------- |
| `invoiceNo`   | string | Invoice number        |
| `invoiceDate` | string | Date of invoice       |
| `poNo`        | string | Purchase order number |
| `orderNo`     | string | Sales order number    |

***

### The `paymentDetails` Object

An `object` containing payment details.

| Attribute            | Type   | Description                                                 |
| -------------------- | ------ | ----------------------------------------------------------- |
| `paymentTerms`       | string | Terms of payment                                            |
| `dueDate`            | string | Payment due date                                            |
| `total`              | string | Total amount due                                            |
| `subtotal`           | string | Subtotal amount                                             |
| `tax`                | string | Tax amount                                                  |
| `discount`           | string | Discount amount                                             |
| `shipping`           | string | Shipping amount                                             |
| `bankingInformation` | object | See [bankingInformation](#paymentdetailsbankinginformation) |

### `paymentDetails.bankingInformation`

| Attribute           | Type   | Description                                        |
| ------------------- | ------ | -------------------------------------------------- |
| `bankName`          | string | Name of the bank                                   |
| `accountHolderName` | string | Name of the account holder                         |
| `accountNumber`     | string | Bank account number                                |
| `iban`              | string | International Bank Account Number (IBAN)           |
| `swiftBicCode`      | string | SWIFT/BIC code of the bank                         |
| `bankAddress`       | object | See [address object](#address-object)              |
| `bankRoutingCode`   | string | Routing code for domestic payments                 |
| `bankCode`          | string | Institution number within Canadian banking network |
| `branchNumber`      | string | Branch-specific code                               |
| `purposeCode`       | string | Specifies the transaction's intent                 |
| `additionalNotes`   | string | Payment instructions or other notes                |

***

### The `others` Object

An `object` containing additional notes.

| Attribute | Type   | Description                                    |
| --------- | ------ | ---------------------------------------------- |
| `notes`   | string | Additional notes such as delivery instructions |

***

### The `lineItems` Object

An `object` detailing the line items in an invoice.

<Warning>
  Note: there is no common structure due to significant variability between invoices! To define your own custom structure, use the [`lineItemStructure`](/api-reference/ai-invoice-parser/#line-item-structure) attribute in your request.
</Warning>

A typical invoice might list purchase items with details such as name, quantity or price of each individual item.

***

### Common Objects

There are a couble of objects which are commonly used in the schema in a few places, these are as follows.

### `address` object

| Attribute       | Type   | Description       |
| --------------- | ------ | ----------------- |
| `streetAddress` | string | Street address    |
| `city`          | string | City name         |
| `state`         | string | State/county name |
| `postalCode`    | string | Postal/ZIP code   |
| `country`       | string | Country code/name |

### `contactInformation` object

| Attribute | Type   | Description                 |
| --------- | ------ | --------------------------- |
| `phone`   | string | Phone number of the vendor  |
| `fax`     | string | Fax number of the vendor    |
| `email`   | string | Email address of the vendor |

## `Example` Payload

<Note>
  To see the request size limits, please refer to the [Request Size Limits](/api-reference/url-input-and-request-limits#pdf-co-request-size).
</Note>

```json theme={null}
{
  "url": "https://pdfco-test-files.s3.us-west-2.amazonaws.com/document-parser/sample-invoice.pdf",
  "callback": "https://example.com/callback/url/you/provided"
}
```

## `Example` Response

<Note>
  To see the main response codes, please refer to the [Response Codes](/api-reference/response-codes).
</Note>

<Note>
  You can use jobId to identify the corresponding callback response. Use the [Job Check](/api-reference/job-check) API to poll the job status.
</Note>

```json theme={null}
{
  "error": false,
  "status": "created",
  "jobId": "7830deca-2e66-11ef-9ad3-8eff830e7461",
  "credits": 100,
  "remainingCredits": 106674,
  "duration": 33
}
```

## `Example` Callback Response

```json theme={null}
{
  "status": "success",
  "message": "Success",
  "pageCount": 1,
  "body": {
    "vendor": {
      "name": "ACME Inc.",
      "address": {
        "streetAddress": "1540  Long Street",
        "city": "Jacksonville",
        "state": "FL",
        "postalCode": "32099",
        "country": "US"
      },
      "contactInformation": {
        "phone": "352-200-0371",
        "fax": "904-787-9468"
      }
    },
    "customer": {
      "billTo": {
        "name": "Lanny Lane Ltd.",
        "address": {
          "streetAddress": "82  Gorby Lane",
          "city": "Columbia",
          "state": "IN",
          "postalCode": "39429",
          "country": "US"
        }
      },
      "shipTo": {
        "name": "Same as recipient"
      }
    },
    "invoice": {
      "invoiceNo": "67893566",
      "invoiceDate": "JAN 5, 2025"
    },
    "paymentDetails": {
      "total": "$1,272.35",
      "subtotal": "$1,262.35",
      "tax": "$10.00",
      "shipping": "$0.00"
    },
    "lineItems": [
      [
        {
          "quantity": "2",
          "description": "Item 1",
          "unit_price": "9.95",
          "total": "19.90"
        },
        {
          "quantity": "5",
          "description": "Item 2",
          "unit_price": "20.00",
          "total": "100.00"
        },
        {
          "quantity": "1",
          "description": "Item 3",
          "unit_price": "19.95",
          "total": "19.95"
        },
        {
          "quantity": "1",
          "description": "Item 4",
          "unit_price": "123.00",
          "total": "123.00"
        },
        {
          "quantity": "10",
          "description": "Item 5",
          "unit_price": "99.95",
          "total": "999.50"
        }
      ]
    ]
  },
  "jobId": "7830deca-2e66-11ef-9ad3-8eff830e7461",
  "credits": 100,
  "remainingCredits": 106472,
  "duration": 33
}
```

## Setting up the Callback URL

The callback URL should be a webhook which listens to responses from the parsing results. You can setup your own webhook or use one from a provider.

<Note>
  If you are unsure about webhooks or callbacks, please read this [Wikipedia article](https://en.wikipedia.org/wiki/Webhook) to get started.
</Note>

## Supported Languages

* **Albanian (Shqip)**
* **Bosnian (Bosanski)**
* **Bulgarian (Български)**
* **Croatian (Hrvatski)**
* **Czech (Čeština)**
* **Danish (Dansk)**
* **Dutch (Nederlands)**
* **English**
* **Estonian (Eesti)**
* **Finnish (Suomi)**
* **French (Français)**
* **German (Deutsch)**
* **Greek (Ελληνικά)**
* **Hungarian (Magyar)**
* **Icelandic (Íslenska)**
* **Italian (Italiano)**
* **Latvian (Latviešu)**
* **Lithuanian (Lietuvių)**
* **Norwegian (Norsk)**
* **Polish (Polski)**
* **Portuguese (Português)**
* **Romanian (Română)**
* **Russian (Русский)**
* **Serbian (Српски)**
* **Slovak (Slovenčina)**
* **Slovenian (Slovenščina)**
* **Spanish (Español)**
* **Swedish (Svenska)**
* **Turkish (Türkçe)**
* **Ukrainian (Українська)**

<Note>
  **Inconsistent URL Encoding in cURL Output:** When using cURL to make API requests, the output JSON may show URL characters encoded as Unicode escape sequences. For example, the ampersand character (`&`) may appear as `\u0026` in the cURL output. This is normal JSON encoding behavior and does not affect the validity of the URL. The URL will function correctly when used, as JSON parsers automatically decode these escape sequences. If you're parsing the response programmatically, your JSON parser will handle this conversion automatically.
</Note>

## Code Samples

<Tabs>
  <Tab title="CURL">
    ```bash theme={null}
    curl -X POST \
    https://api.pdf.co/v1/ai-invoice-parser
    ```
  </Tab>

  <Tab title="JavaScript/Node.js">
    ```javascript theme={null}
    var https = require("https");

    // The authentication key (API Key).
    // Get your own by registering at https://app.pdf.co
    const API_KEY = "YOUR_API_KEY_HERE";

    // Direct URL of the source PDF file
    // You can also upload your own file into PDF.co and use it as url. Check "Upload File" samples for code snippets: https://github.com/bytescout/pdf-co-api-samples/tree/master/File%20Upload/
    const SourceFileUrl = "https://pdfco-test-files.s3.us-west-2.amazonaws.com/document-parser/sample-invoice.pdf";

    // Prepare request to `AI Invoice Parser` API endpoint
    var queryPath = `/v1/ai-invoice-parser`;

    // JSON payload for api request
    var jsonPayload = JSON.stringify({
        url: SourceFileUrl
    });

    var reqOptions = {
        host: "api.pdf.co",
        method: "POST",
        path: queryPath,
        headers: {
            "x-api-key": API_KEY,
            "Content-Type": "application/json",
            "Content-Length": Buffer.byteLength(jsonPayload, 'utf8')
        }
    };

    var postRequest = https.request(reqOptions, (response) => {
        let responseData = '';

        response.on("data", (chunk) => {
            responseData += chunk;
        });

        response.on("end", () => {
            try {
                // Parse JSON response
                var data = JSON.parse(responseData);
                if (data.error == false) {
                    console.log(`Job #${data.jobId} has been created!`);
                    checkIfJobIsCompleted(data.jobId, data.url);
                }
                else {
                    // Service reported error
                    console.log(data.message);
                }
            } catch (error) {
                console.error("Error parsing JSON response:", error);
            }
        });
    }).on("error", (e) => {
        // Request error
        console.log(e);
    });

    // Write request data
    postRequest.write(jsonPayload);
    postRequest.end();

    function checkIfJobIsCompleted(jobId, resultFileUrl) {
        let queryPath = `/v1/job/check`;
        // JSON payload for api request
        let jsonPayload = JSON.stringify({
            jobid: jobId
        });
        let reqOptions = {
            host: "api.pdf.co",
            path: queryPath,
            method: "POST",
            headers: {
                "x-api-key": API_KEY,
                "Content-Type": "application/json",
                "Content-Length": Buffer.byteLength(jsonPayload, 'utf8')
            }
        };
        // Send request
        var postRequest = https.request(reqOptions, (response) => {
            let responseData = '';

            response.setEncoding("utf8");

            response.on("data", (chunk) => {
                responseData += chunk;
            });

            response.on("end", () => {
                try {
                    // Parse JSON response
                    let data = JSON.parse(responseData);
                    console.log(`Checking Job #${jobId}, Status: ${data.status}, Time: ${new Date().toLocaleString()}`);

                    if (data.status == "working") {
                        // Check again after 3 seconds
                        setTimeout(function(){ checkIfJobIsCompleted(jobId, resultFileUrl);}, 3000);
                    }
                    else if (data.status == "success") {
                        console.log("** Response **")
                        console.log(data);
                    }
                    else {
                        console.log(`Operation ended with status: "${data.status}".`);
                    }
                } catch (error) {
                    console.error("Error parsing JSON response:", error);
                }
            });
        });

        // Write request data
        postRequest.write(jsonPayload);
        postRequest.end();
    }
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    import os
    import requests # pip install requests
    import time
    import datetime

    # The authentication key (API Key).
    # Get your own by registering at https://app.pdf.co
    API_KEY = "******************************************"

    # Base URL for PDF.co Web API requests
    BASE_URL = "https://api.pdf.co/v1"

    # Direct URL of source PDF file.
    # You can also upload your own file into PDF.co and use it as url. Check "Upload File" samples for code snippets: https://github.com/bytescout/pdf-co-api-samples/tree/master/File%20Upload/
    SourceFileURL = "https://pdfco-test-files.s3.us-west-2.amazonaws.com/document-parser/sample-invoice.pdf"


    def main(args = None):
        getParsedInvoice(SourceFileURL)

    def getParsedInvoice(uploadedFileUrl):
        """AI Invoice Parser using PDF.co Web API"""

        # Prepare requests params as JSON
        # See documentation: https://apidocs.pdf.co
        parameters = {}
        parameters["url"] = uploadedFileUrl

        # Prepare URL for 'AI Invoice Parser' API request
        url = "{}/ai-invoice-parser".format(BASE_URL)

        # Execute request and get response as JSON
        response = requests.post(url, data=parameters, headers={ "x-api-key": API_KEY })
        if (response.status_code == 200):
            json = response.json()

            if json["error"] == False:
                # Asynchronous job ID
                jobId = json["jobId"]

                # Check the job status in a loop.
                # If you don't want to pause the main thread you can rework the code
                # to use a separate thread for the status checking and completion.
                while True:
                    status = checkJobStatus(jobId) # Possible statuses: "working", "failed", "aborted", "success".

                    # Display timestamp and status (for demo purposes)
                    print(datetime.datetime.now().strftime("%H:%M.%S") + ": " + status)

                    if status == "success":
                        break
                    elif status == "working":
                        # Pause for a few seconds
                        time.sleep(3)
                    else:
                        print(status)
                        break
            else:
                # Show service reported error
                print(json["message"])
        else:
            print(f"Request error: {response.status_code} {response.reason}")


    def checkJobStatus(jobId):
        """Checks server job status"""

        url = f"{BASE_URL}/job/check?jobid={jobId}"

        response = requests.get(url, headers={ "x-api-key": API_KEY })
        if (response.status_code == 200):
            json = response.json()

            if(json["status"]):
                print("** Response **")
                print(json)

            return json["status"]
        else:
            print(f"Request error: {response.status_code} {response.reason}")

        return None

    if __name__ == '__main__':
        main()
    ```
  </Tab>

  <Tab title="C#">
    ```csharp theme={null}
    using Newtonsoft.Json;
    using Newtonsoft.Json.Linq;
    using System;
    using System.Collections.Generic;
    using System.Net;
    using System.Threading;

    namespace PDFcoApiExample
    {
      class Program
      {
        // The authentication key (API Key).
        // Get your own by registering at https://app.pdf.co
        const String API_KEY = "***********************************";

            // Direct URL of Source PDF file
            // You can also upload your own file into PDF.co and use it as url. Check "Upload File" samples for code snippets: https://github.com/bytescout/pdf-co-api-samples/tree/master/File%20Upload/
            const string SourceFileURL = "https://pdfco-test-files.s3.us-west-2.amazonaws.com/document-parser/sample-invoice.pdf";

        static void Main(string[] args)
        {
                // Create standard .NET web client instance
                WebClient webClient = new WebClient();

          // Set API Key
          webClient.Headers.Add("x-api-key", API_KEY);

                // URL for `AI Invoice Parser` API call
                string url = "https://api.pdf.co/v1/ai-invoice-parser";

          // Prepare requests params as JSON
          Dictionary<string, object> parameters = new Dictionary<string, object>();
          parameters.Add("url", SourceFileURL);

          // Convert dictionary of params to JSON
          string jsonPayload = JsonConvert.SerializeObject(parameters);

                try
                {
                    // Execute POST request with JSON payload
                    string response = webClient.UploadString(url, jsonPayload);

                    // Parse JSON response
                    JObject json = JObject.Parse(response);

                    if (json["error"].ToObject<bool>() == false)
                    {
                        // Asynchronous job ID
                        string jobId = json["jobId"].ToString();

                        // Check the job status in a loop.
                        // If you don't want to pause the main thread you can rework the code
                        // to use a separate thread for the status checking and completion.
                        do
                        {
                            string job_response = "";
                            string status = CheckJobStatus(jobId, out job_response); // Possible statuses: "working", "failed", "aborted", "success".

                            // Display timestamp and status (for demo purposes)
                            Console.WriteLine(DateTime.Now.ToLongTimeString() + ": " + status);

                            if (status == "success")
                            {
                                Console.WriteLine("** Final Response **");
                                Console.WriteLine(job_response);
                                break;
                            }
                            else if (status == "working")
                            {
                                // Pause for a few seconds
                                Thread.Sleep(3000);
                            }
                            else
                            {
                                Console.WriteLine(status);
                                break;
                            }
                        }
                        while (true);
                    }
                    else
                    {
                        Console.WriteLine(json["message"].ToString());
                    }
                }
                catch (WebException e)
                {
                    Console.WriteLine(e.ToString());
                }

                webClient.Dispose();

          Console.WriteLine();
          Console.WriteLine("Press any key...");
          Console.ReadKey();
        }

            static string CheckJobStatus(string jobId, out string response)
            {
                using (WebClient webClient = new WebClient())
                {
                    // Set API Key
                    webClient.Headers.Add("x-api-key", API_KEY);

                    string url = "https://api.pdf.co/v1/job/check?jobid=" + jobId;

                    response = webClient.DownloadString(url);
                    JObject json = JObject.Parse(response);

                    return Convert.ToString(json["status"]);
                }
            }
        }
    }
    ```
  </Tab>

  <Tab title="Java">
    ```java theme={null}
    package com.company;

    import com.google.gson.JsonObject;
    import com.google.gson.JsonParser;
    import com.google.gson.JsonPrimitive;
    import okhttp3.*;

    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.OutputStream;
    import java.nio.charset.StandardCharsets;
    import java.nio.file.Files;
    import java.nio.file.Path;
    import java.nio.file.Paths;
    import java.time.LocalDateTime;
    import java.time.format.DateTimeFormatter;

    public class Main {
        // The authentication key (API Key).
        // Get your own by registering at https://app.pdf.co
        final static String API_KEY = "********************************";

        // (!) Make asynchronous job
        final static boolean Async = true;

        public static void main(String[] args) throws IOException {

            // Source PDF file
            // You can also upload your own file into PDF.co and use it as url. Check "Upload File" samples for code snippets: https://github.com/bytescout/pdf-co-api-samples/tree/master/File%20Upload/
            final String SourceFileUrl = "https://pdfco-test-files.s3.us-west-2.amazonaws.com/document-parser/sample-invoice.pdf";

            // Create HTTP client instance
            OkHttpClient webClient = new OkHttpClient();

            // AI PARSE INVOICE
            ParseInvoice(webClient, SourceFileUrl);
        }

        public static void ParseInvoice(OkHttpClient webClient, String uploadedFileUrl) throws IOException {
            // Prepare POST request body in JSON format
            JsonObject jsonBody = new JsonObject();
            jsonBody.add("url", new JsonPrimitive(uploadedFileUrl));

            RequestBody body = RequestBody.create(MediaType.parse("application/json"), jsonBody.toString());

            // Prepare URL for AI Invoice Parser API call.
            // See documentation: https://developer.pdf.co/api/ai-invoice-parser
            String query = "https://api.pdf.co/v1/ai-invoice-parser";

            DateTimeFormatter dtf = DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm:ss");

            // Prepare request to `Document Parser` API
            Request request = new Request.Builder()
                    .url(query)
                    .addHeader("x-api-key", API_KEY) // (!) Set API Key
                    .addHeader("Content-Type", "application/json")
                    .post(body)
                    .build();

            // Execute request
            Response response = webClient.newCall(request).execute();

            if (response.code() == 200) {
                // Parse JSON response
                JsonObject json = new JsonParser().parse(response.body().string()).getAsJsonObject();

                boolean error = json.get("error").getAsBoolean();
                if (!error) {
                    // Asynchronous job ID
                    String jobId = json.get("jobId").getAsString();

                    System.out.println("Job#" + jobId + ": has been created. - " + dtf.format(LocalDateTime.now()));

                    // Check the job status in a loop.
                    // If you don't want to pause the main thread you can rework the code
                    // to use a separate thread for the status checking and completion.
                    do {

                        String status = CheckJobStatus(webClient, jobId); // Possible statuses: "working", "failed", "aborted", "success"

                        System.out.println("Job#" + jobId + ": " + status + " - " + dtf.format(LocalDateTime.now()));

                        if (status.compareToIgnoreCase("success") == 0) {
                            break;
                        } else if (status.compareToIgnoreCase("working") == 0) {
                            // Pause for a few seconds
                            try {
                                Thread.sleep(3000);
                            } catch (InterruptedException ex) {
                                Thread.currentThread().interrupt(); // restore interrupted status
                            }
                        } else {
                            System.out.println(status);
                            break;
                        }
                    } while (true);

                } else {
                    // Display service reported error
                    System.out.println(json.get("message").getAsString());
                }
            } else {
                // Display request error
                System.out.println(response.code() + " " + response.message());
            }
        }


        // Check Job Status
        private static String CheckJobStatus(OkHttpClient webClient, String jobId) throws IOException {

            String url = "https://api.pdf.co/v1/job/check?jobid=" + jobId;
            String status = "";

            // Prepare request
            Request request = new Request.Builder()
                    .url(url)
                    .addHeader("x-api-key", API_KEY) // (!) Set API Key
                    .build();

            // Execute request
            Response response = webClient.newCall(request).execute();

            if (response.code() == 200) {
                // Parse JSON response
                JsonObject json = new JsonParser().parse(response.body().string()).getAsJsonObject();

                status = json.get("status").getAsString();

                if(status.equals("success")){
                    System.out.println(json);
                }

                return status;
            } else {
                // Display request error
                System.out.println(response.code() + " " + response.message());
            }

            return "Failed";
        }
    }
    ```
  </Tab>

  <Tab title="PHP">
    ```php theme={null}
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>AI Invoice Parser example.</title>
    </head>
    <body>

    <?php

    // PDF.co "AI Invoice Parser" code snippet.

    // The authentication key (API Key).
    // Get your own by registering at https://app.pdf.co
    $apiKey = "YOUR_API_KEY";

    // Direct URL of Source PDF file
    // You can also upload your own file into PDF.co and use it as url. Check "Upload File" samples for code snippets: https://github.com/bytescout/pdf-co-api-samples/tree/master/File%20Upload/
    $sourceFileUrl = "https://pdfco-test-files.s3.us-west-2.amazonaws.com/document-parser/sample-invoice.pdf";

    // Prepare URL for `AI Invoice Parser` API call
    $url = "https://api.pdf.co/v1/ai-invoice-parser";

    // Prepare requests params
    $parameters = array();
    $parameters["url"] = $sourceFileUrl;

    // Create Json payload
    $data = json_encode($parameters);

    // Create request
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_HTTPHEADER, array("x-api-key: " . $apiKey, "Content-type: application/json"));
    curl_setopt($curl, CURLOPT_URL, $url);
    curl_setopt($curl, CURLOPT_POST, true);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($curl, CURLOPT_POSTFIELDS, $data);

    // Execute request
    $result = curl_exec($curl);
    echo $result . "<br/>";

    if (curl_errno($curl) == 0)
    {
        $status_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);

        if ($status_code == 200)
        {
            $json = json_decode($result, true);

            if (!isset($json["error"]) || $json["error"] == false)
            {
                // Asynchronous job ID
                $jobId = $json["jobId"];

                // Check the job status in a loop
                do
                {
                    $status = CheckJobStatus($jobId, $apiKey); // Possible statuses: "working", "failed", "aborted", "success".

                    // Display timestamp and status (for demo purposes)
                    echo "<p>" . date(DATE_RFC2822) . ": " . $status . "</p>";

                    if ($status == "success")
                    {
                        break;
                    }
                    else if ($status == "working")
                    {
                        // Pause for a few seconds
                        sleep(3);
                    }
                    else
                    {
                        echo $status . "<br/>";
                        break;
                    }
                }
                while (true);
            }
            else
            {
                // Display service reported error
                echo "<p>Error: " . $json["message"] . "</p>";
            }
        }
        else
        {
            // Display request error
            echo "<p>Status code: " . $status_code . "</p>";
            echo "<p>" . $result . "</p>";
        }
    }
    else
    {
        // Display CURL error
        echo "Error: " . curl_error($curl);
    }

    // Cleanup
    curl_close($curl);


    function CheckJobStatus($jobId, $apiKey)
    {
        $status = null;

        // Create URL
        $url = "https://api.pdf.co/v1/job/check";

        // Prepare requests params
        $parameters = array();
        $parameters["jobid"] = $jobId;

        // Create Json payload
        $data = json_encode($parameters);

        // Create request
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_HTTPHEADER, array("x-api-key: " . $apiKey, "Content-type: application/json"));
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_POST, true);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($curl, CURLOPT_POSTFIELDS, $data);

        // Execute request
        $result = curl_exec($curl);

        if (curl_errno($curl) == 0)
        {
            $status_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);

            if ($status_code == 200)
            {
                $json = json_decode($result, true);

                if (!isset($json["error"]) || $json["error"] == false)
                {
                    $status = $json["status"];
                    echo "<br/><br/><p>== Final Response ==</p>";
                    echo $result;
                }
                else
                {
                    // Display service reported error
                    echo "<p>Error: " . $json["message"] . "</p>";
                }
            }
            else
            {
                // Display request error
                echo "<p>Status code: " . $status_code . "</p>";
                echo "<p>" . $result . "</p>";
            }
        }
        else
        {
            // Display CURL error
            echo "Error: " . curl_error($curl);
        }

        // Cleanup
        curl_close($curl);

        return $status;
    }

    ?>

    </body>
    </html>
    ```
  </Tab>
</Tabs>
