Introduction

Welcome to the PamBill API. On this page you can learn how to send order data to PamBill. With the API you can easily create an application to connect to PamBill and automatically import order data from any external system.

The connection is done with the API keys, which you can find in your PamBill account. These keys are generated per shop so that you can send order data to a particular shop, in case you have multiple shops configured in PamBill. Note: an active Pro-Package is required to use the API, the other packages do not include the API.

There are no limitations on how many shops you can send data to or to the amount of orders you can send to PamBill (we do have some flood protection though, see the API limitations for details).

Should you have any questions about the API, please contact our support at: https://support.pambill.com/

The current API version is 1.2.

Help & Support

Contact our support team by opening a ticket at https://support.pambill.com/ if you need help when creating an integration or want to request a feature or an API extension.

Getting API keys

API keys are shop-specific. To find them, open the Shops page in PamBill at https://www.pambill.com/shops-manage/ and click the shop name to open the shop for editing. Scroll down to the API tokens section and copy the keys.

The public key is the TOKEN of the API request.

The secret key is used when calculating the CHECKSUM of the request.

Sending Requests to PamBill API

All requests need to be sent to https://www.pambill.com/api

Only HTTP POST requests are accepted. Do not send the data as file attachment. Do not use enctype="multipart/form-data". Instead, send plain raw POST requests.

Any tool or technology capable of sending HTTP POST requests can be used as the client, for instance, a web page in a browser. Below is a working example of sending a request to PamBill API using jQuery. If you want to test it, set your own values of token, secret, origin and data.

<!-- Include jQuery and Crypto.js -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
<script type="text/javascript">
    function sendDataToPamBill() {
        const api_version = '1.2';
        const action = 'import';
        // the public shop token from PamBill
        const token = 'UVxO25b0rAa11E8a9fAaBD02ZIMIvKc6';
        // the secret shop token from PamBill
        // NOTE: Never include secret tokens into a public page,
        // as the page source can be viewed by anyone
        const secret = 'k2FLfgLU3A68s36WVoa2RLcx3Kl5w2DM';
        // the name of your app
        const origin = 'ExporterBrandApp';

        // an array of orders to be imported
        // see the DATA section for sample data
        const data = [{}];

        // generate the CALL_ID
        let call_id = Date.now().toString();
        // add the random part to make CALL_ID exactly 32 chars long
        let counter = call_id.length;
        const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
        while (counter < 32) {
            call_id += chars.charAt(Math.floor(Math.random() * chars.length));
            counter += 1;
        }

        // calculate the checksum
        let checksum = token + secret + call_id;
        // hash the result
        checksum = CryptoJS.SHA256(checksum).toString(CryptoJS.enc.Hex);

        // send the request to PamBill API
        let request = {
            "VERSION": api_version,
            "ORIGIN": origin,
            "TOKEN": token,
            "CALL_ID": call_id,
            "ACTION": action,
            "CHECKSUM": checksum,
            "DATA": data
        };

        $.ajax({
            type: "POST",
            url: 'https://www.pambill.com/api',
            data: JSON.stringify(request),
            success: function(response) {
                // console.log(response);
                let responseObj = JSON.parse(response);

                if (responseObj.STATE == "ERROR") {
                    // request rejected
                    console.log(responseObj.ERROR.CODE);
                    console.log(responseObj.ERROR.MESSAGE);
                }

                if (responseObj.STATE == "OK") {
                    // request accepted
                    if (responseObj.DATA.hasOwnProperty('SUCCESS')) {
                        console.log('Successfully imported orders: ' + JSON.stringify(responseObj.DATA.SUCCESS));
                    }
                    if (responseObj.DATA.hasOwnProperty('ERROR')) {
                        console.log('Import failed of orders: ' + JSON.stringify(responseObj.DATA.ERROR));
                    }
                }
            }
        });
    }

    sendDataToPamBill();
</script>

A simple practical way of sending requests to the API is using CURL. E.g.

curl -i -X POST -H 'Content-Type: application/json' -d '{REQUEST as JSON}' https://www.pambill.com/api

Importing the Orders

PamBill imports the orders into the shop identified by the TOKEN field of the API request. If you have more than one shop in the PamBill account, use the respective API tokens for each shop when you send the data to PamBill. Assigning orders to their shops is necessary for PamBill to detect duplicated orders.

Unless you send the orders from checkout or from the order page, combine the orders into packs. The DATA field accepts an array of entities, and it is much more efficient to send 100 orders in one request than 100 requests containing 1 order each.

As a rule of thumb, we recommend sending 50-100 orders to PamBill in an API call. This will provide for performance and decrease the chance of a timeout. The maximum allowed number of orders in one API request is 500.

Mandatory Fields

Each request must include the following fields with their values.

VERSION

The version of the API. The current version is “1.2”.
Sample values:
• 1.2

ORIGIN

The short custom name of the system that sends the data to PamBill. Please use the same value for all API requests. This value will identify your application at PamBill.

The allowed length is from 3 to 32 characters. Allowed characters: [0-9a-zA-Z_]. Numbers are only to be used if they are part of the name of the app, e.g. 1signal, and should NOT represent the version of your app.

If possible, start each meaningful word with a capital letter.
Sample values:
• SuperExportApp
• Thinkific_Export_by_Anna
• EshopExporter
• WooCommerceOrders

TOKEN

Represents the shop in PamBill. This is the public token that is shown on the Edit Shop page in PamBill and is automatically generated. It needs to be passed to the API client by the PamBill user.

Must be exactly 32 characters long.
Sample values:
• DF892KQY9A969g2o14I06uJDbAJk6aI8

CALL_ID

Unique value for each API call made for the given TOKEN. Used as the nonce, to prevent a replay attack. As a suggestion, it can be a timestamp (milli- or microseconds) concatenated with a random alphanumeric tail to be exactly 32 characters long.

Either the timestamp or the tail, or both, need to change with each call, therefore we advise against using only a timestamp and a fixed tail, because the timestamp value is not guaranteed to change when the calls are sent rapidly one after another.

Please also note that the length of the timestamp can change with time, so it might be a good idea to construct the string, and then use the first 32 characters of it.

Must be exactly 32 characters long. The allowed characters are [0-9a-zA-Z_]
Sample values:
• 1661240906651DF892KQY9A969g2o14e
• 1661240906651_DF892KQY9A969g2o14
• 1661240906651987_DF892KQY9A969g2
• 16612409066519874037492515795326

The following error is returned if a request with the same CALL_ID and TOKEN had been logged by the API before:

{"STATE":"ERROR","ERROR":{"CODE":"ERR_API_DUPLICATED_REQUEST","MESSAGE":"CALL_ID must be unique for each request"}}

ACTION

The value of this field tells PamBill the purpose of this call.

The ACTION parameter replaces the POST, GET, PUT, PATCH and DELETE HTTP methods that are traditionally used in REST APIs. Instead, we only accept POST requests to the single URL endpoint, and the operation is defined by the action.

E.g. if the API client needs to get an external link to an invoice, he needs to send a POST request with the respective ACTION, and get the data from the response.

Requests with non-supported ACTION are rejected. Service actions, e.g. validate_token, validate_account, pambill_package and latest_order_number, do not require an active Pro-Package.

Here is the list of currently supported actions.

ACTION Description DATA Response example(s)
import Import orders from any online or offline store into PamBill. See the DATA section of this guide for the data format reference and sample order data.

If the orders have been imported, a UUID is returned for each order, that can be used to reference the order in PamBill
array of orders {"STATE":"OK","DATA":{"SUCCESS":{"COUNT":1,"DATA":[{"order_number":1002,"uuid":"ZIe8CD3FMU1143zn"}]},"ERROR":{"COUNT":1,"DATA":[{"order_number":1001,"error":"ERR_INVOICE_ALREADY_EXISTS"}]}}}
import_shopify Import orders from a Shopify store into PamBill. The orders are typically returned by the Shopify GraphQL Admin API. Please contact PamBill support for the list of required order fields.

If the orders have been imported, a UUID is returned for each order, that can be used to reference the order in PamBill
array of orders {"STATE":"OK","DATA":{"SUCCESS":{"COUNT":1,"DATA":[{"order_number":1002,"uuid":"ZIe8CD3FMU1143zn"}]},"ERROR":{"COUNT":1,"DATA":[{"order_number":1001,"error":"ERR_INVOICE_ALREADY_EXISTS"}]}}}
validate_token Validate that both public and secret tokens are recognized by PamBill. The secret token is not included in the request, but is used for calculating the CHECKSUM.

ERR_API_CHECKSUM_INCORRECT means that either the secret token is wrong, or you calculate the CHECKSUM incorrectly
'' {"STATE":"OK","DATA":[]}

{"STATE":"ERROR","ERROR":{"CODE":"ERR_API_CHECKSUM_INCORRECT","MESSAGE":""}}
validate_account Validate that the PamBill account has an active Pro or Trial package.

ERR_API_PRO_USERS_ONLY means that the user does not have the package, and orders cannot be imported at the moment. Please do not rely on the MESSAGE returned, as it may be changed or translated in the future
'' {"STATE":"OK","DATA":[]}

{"STATE":"ERROR","ERROR":{"CODE":"ERR_API_PRO_USERS_ONLY","MESSAGE":"An active Professional package is required to import orders into PamBill. To upgrade or convert your current package to Pro, please visit https://www.pambill.com/shop/extend/"}}
pambill_package Returns the current PamBill package, or NONE if the PamBill user has no active package. The package renewal link is also returned.

The package can have values NONE, PRO, BASIC, STARTER. PRO is also returned in case of the free trial at PamBill. The expiration_date is the number of seconds since the Unix epoch. expiration_date_formatted is formatted according to the PamBill account settings
'' {"STATE":"OK","DATA":{"package":"NONE","expiration_date":"","expiration_date_formatted":"","renewal_link":"https://www.pambill.com/shop/extend/"}}

{"STATE":"OK","DATA":{"package":"PRO","expiration_date":1703958918,"expiration_date_formatted":"30. December 2028","renewal_link":"https://www.pambill.com/shop/extend/"}}

{"STATE":"OK","DATA":{"package":"STARTER","expiration_date":1703958918,"expiration_date_formatted":"30.12.2028","renewal_link":"https://www.pambill.com/shop/extend/"}}
latest_order_number Returns the number of the latest order found in the given shop (identified by the TOKEN of the request) in PamBill. The orders are sorted by the date of the order, as the order number is not always sortable. Invoices that were manually created in PamBill, are ignored during this search. Empty order number is returned if no order is found in PamBill.

latest_order_date is also returned, for reference
'' {"STATE":"OK","DATA":{"latest_order_number":"","latest_order_date":""}}

{"STATE":"OK","DATA":{"latest_order_number":"1000","latest_order_date":"2024-12-23 11:38:32"}}

CHECKSUM

The CHECKSUM is used to confirm that the request is authorized. This value allows PamBill to validate that the request was created using the correct secret token.

CHECKSUM needs to be calculated for each request using the secret token found on the Edit Shop page in PamBill. The token needs to be passed to the API client by the PamBill user. Both public and secret tokens are found on the Edit Shop page in PamBill.

The calculation formula is this:

CHECKSUM = sha256 ( TOKEN + Secret + CALL_ID )

PHP code to calculate the checksum:

// calculate the CHECKSUM
// $token is the TOKEN of the request
// $secret is the secret API token that matches the TOKEN of the request
// $call_id is the CALL_ID of the request
$checksum = hash('sha256', $token . $secret . $call_id);

JavaScript code to calculate the checksum:

// in this example, we use Crypto.js for easy hashing
// https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js
let checksum = token + secret + call_id;

// hash the result
checksum = CryptoJS.SHA256(checksum).toString(CryptoJS.enc.Hex);

DATA

The data, as JSON. If the ACTION doesn't require any DATA, set DATA to an empty string.

If the ACTION is "import", we expect the DATA to be an array of orders.

Sample value:
• [{_order1_},{_order2_}]
• ''

Required fields

The required fields of each order:
• order_number
• order_date
• currency
• billing_address -> email
• items array with at least one item

The required fields of each item:
• quantity
• price_gross
• name

If the order amount exceeds 250 euros, the invoice needs to contain the full name and address of the customer (recipient of the service). It is a legal requirement. The customer is represented by the billing_address of the order data.

[{
    "//documentation0": "NOTE: These \"//documentation*\" properties are NOT used by the parser. Please remove them before deploying the API client and sending requests to PamBill API",

    "//documentation1": "If you do not have the data, just do not include the value (set it to null or empty string) and see if the order can be imported. We use default values where possible",
    "//documentation2": "Some values are mandatory: \"order_number\", \"billing_address\" with the \"email\", the \"items\" array, and more",

    "//documentation3": "All the prices are expected to be gross, i.e. with VAT included.",
    "//documentation4": "PamBill applies a set of VAT extraction rules at import to provide for correct VAT on the invoices, based on the Settings.",
    "//documentation5": "We support OSS, EU VAT exemption, small traders, selling from EU to non-EU, using the reduced VAT rate, and more.",
    "//documentation6": "Please review the VAT Settings at https://www.pambill.com/user/company/#vat_number",

    "//documentation7": "We also provide the following fields/flags that can be used to control the VAT rate at import.",
    "//documentation8": "\"apply_reduced_vat\": set to true for reduced-VAT products. The alternative is including the reduced-VAT code into the product name or variant. See the Reduced VAT settings at https://www.pambill.com/user/company/#vat_number",
    "//documentation9": "\"apply_no_vat\": set to true for VAT-exempt products. The alternative is including the zero-VAT code into the product name or variant. See the Reduced VAT settings at https://www.pambill.com/user/company/#vat_number",
    "//documentation10": "\"special_vat_rate\": e.g. \"7.7\". This field allows overriding the VAT rate at import and deprecates the advanced VAT extraction logic that PamBill would use otherwise.",
    "//documentation11": "The typical usage of the \"special_vat_rate\" is for products that need to have special VAT rates, e.g. 3.7% instead of the standard 2.5% reduced VAT in Switzerland.",

    "//documentation12": "\"order_number\": the format can be \"01001\", \"#1001\", \"#01001\", \"1001\"",
    "//documentation13": "\"order_date\": we use the strtotime() PHP function to parse the date and time",
    "//documentation14": "\"currency\": EUR, USD, CHF, etc.",
    "//documentation15": "\"preferred_language\": an ISO language code, will be stored in the Customer in PamBill and later used in the invoices, e-mails, etc.",
    "//documentation16": "\"prices_include_vat\": ALWAYS true. Send us the GROSS values only. PamBill will extract the VAT at import",

    "order_number": "1001",
    "order_date": "2024-12-23T11:00:00-05:00",

    "currency": "USD",
    "preferred_language": "en",
    "prices_include_vat": true,

    "payment": {
        "//documentation0": "\"provider\": can be a string or an array. E.g. \"Credit Card\" or [\"PayPal\", \"Cash on Delivery (COD)\"]. See the supported payment types at https://www.pambill.com/user/company/ in the Payment and Shipping section, or supply your value and let us know in a support request",
        "//documentation1": "\"paid_at\": if provided, the order will be set into the Paid state at import. The order will also become Paid if the \"provider\" is of a pre-paid type, e.g. Credit Card, PayPal, Direct Debit, etc.",
        "//documentation2": "\"price_gross\": if provided, the order will be set into the Paid state at import. The order will also become Paid if the \"provider\" is of a pre-paid type, e.g. Credit Card, PayPal, Direct Debit, etc.",

        "provider": "PayPal",
        "paid_at": null,
        "price_gross": null
    },

    "discount": {
        "//documentation0": "\"code\": discount or voucher name",
        "//documentation1": "\"price_gross\" can be positive or negative, PamBill will handle both as negative",

        "price_gross": 10.0,
        "code": "Gift Voucher"
    },

    "refund": {
        "//documentation0": "This section covers both cancellation and refund. If the \"price_gross\" is null, it is a cancellation, otherwise a refund",

        "//documentation1": "\"price_gross\": null in case of cancellation. Total gross amount of all refunds for this order. If the refunded amount is smaller than the total, it is a partial refund. It is possible to import the same order with increased refunded amount into PamBill a few times, to update the partially refunded amount in the invoice",
        "//documentation2": "\"price_gross\" can be positive or negative, PamBill will handle both as negative",
        "//documentation3": "\"cancelled_at\": cancellation or refund datetime",

        "price_gross": 100.0,
        "cancelled_at": null,
        "reason": null
    },

    "billing_address": {
        "//documentation0": "\"billing_address\" represents the Customer entity in PamBill. The \"email\" is mandatory",

        "//documentation1": "\"company_vat\": if present and valid, the VAT number will be used for EU VAT exemption. Needs to match the billing country",
        "//documentation2": "\"country_code\": ISO country code",
        "//documentation3": "\"salutation\": Mr., Ms., Mrs, Señor, Señora, Herr, etc. or null",

        "//documentation4": "\"first_name\": provide either \"name\", or \"first_name\" and \"last_name\", or all of them",
        "//documentation5": "\"last_name\": provide either \"name\", or \"first_name\" and \"last_name\", or all of them",
        "//documentation6": "\"name\": provide either \"name\", or \"first_name\" and \"last_name\", or all of them",

        "//documentation7": "\"notes\": Billing Notes",
        "//documentation8": "\"region\": if present, will be printed in the address",

        "address1": "2259 Park Ct",
        "address2": "Apartment 5",
        "city": "Drayton Valley",
        "company": "Gorski & Partners",
        "company_vat": "DE250438265",
        "country_code": "CA",
        "email": "bob.norman@mail.example.com",
        "salutation": "Mr.",
        "first_name": "Christopher",
        "last_name": "Gorski",
        "name": "Christopher Gorski",
        "notes": null,
        "phone": "+13125551212",
        "region": "Alberta",
        "zip": "T0E 0M0"
    },

    "shipping_address": {
        "//documentation0": "\"shipping_address\" may be empty, e.g. when no delivery is needed, or when it matches the \"billing_address\"",

        "//documentation1": "\"notes\": Shipping Notes",

        "address1": "123 Amoebobacterieae St",
        "address2": "",
        "city": "Ottawa",
        "company": null,
        "country_code": "CA",
        "email": "bob.bobsen@mail.example.com",
        "salutation": null,
        "first_name": "Bob",
        "last_name": "Bobsen",
        "name": "Bob Bobsen",
        "notes": null,
        "phone": "555-625-1199",
        "region": "Ontario",
        "zip": "K2P0V6"
    },

    "items": [
        {
            "//documentation0": "\"price_gross\": gross price of one item",

            "//documentation1": "The priority (descending): \"special_vat_rate\", \"apply_no_vat\", \"apply_reduced_vat\"",
            "//documentation2": "\"special_vat_rate\": e.g. \"3.7\". This can be used to force the special VAT rate",
            "//documentation3": "\"apply_no_vat\": set to true is this product is VAT-exempt",
            "//documentation4": "\"apply_reduced_vat\": apply the reduced VAT rate at import to this item / product",

            "quantity": 1,
            "price_gross": "199.99",
            "sku": "IPOD-342-N",
            "name": "IPod Nano",
            "variant": "Pink",
            "apply_reduced_vat": false,
            "apply_no_vat": false,
            "special_vat_rate": null
        },
        {
            "quantity": 2,
            "price_gross": "15",
            "sku": "CASE-01",
            "name": "Universal Phone Case",
            "variant": null,
            "apply_reduced_vat": false,
            "apply_no_vat": false,
            "special_vat_rate": null
        },
        {
            "quantity": 1,
            "price_gross": "9.99",
            "sku": null,
            "name": "100% Arabica",
            "variant": "500g",
            "apply_reduced_vat": true,
            "apply_no_vat": false,
            "special_vat_rate": null
        },
        {
            "quantity": 1,
            "price_gross": "21.29",
            "sku": null,
            "name": "Bio Espresso Decaf",
            "variant": "1000g",
            "apply_reduced_vat": false,
            "apply_no_vat": false,
            "special_vat_rate": "3.7"
        },
        {
            "quantity": 1,
            "price_gross": "10.00",
            "sku": null,
            "name": "Something VAT-exempt",
            "variant": null,
            "apply_reduced_vat": false,
            "apply_no_vat": true,
            "special_vat_rate": null
        }
    ],

    "shipping": {
        "//documentation0": "The delivery / post fee VAT rate is set in PamBill VAT Settings.",
        "//documentation1": "In case the invoice items have reduced VAT, the delivery / post fee VAT will also be reduced.",

        "delivery": {
            "price_gross": "9.99",
            "type": null
        },
        "post_fee": {
            "price_gross": null,
            "type": null
        }
    }
}]

API Limitations

The following limits are applied to all API requests to prevent misuse and overload.

Number or requests

The number of all API requests sent to one PamBill shop (the TOKEN) cannot exceed 1000 requests per 10 minutes. ERR_API_TOO_MANY_REQUESTS is returned.

{"STATE":"ERROR","ERROR":{"CODE":"ERR_API_TOO_MANY_REQUESTS","MESSAGE":""}}

Request size

The size of each JSON-encoded API request cannot exceed 64Mb. The chance that you hit it should be neglectably small because of the other limits, so please let us know in case you do. ERR_API_REQUEST_TOO_BIG is returned.

{"STATE":"ERROR","ERROR":{"CODE":"ERR_API_REQUEST_TOO_BIG","MESSAGE":"65536kB max"}}

Number of entities

The number of entities in the DATA field of any request cannot exceed 500. ERR_API_TOO_MANY_DATA_ENTITIES is returned. The recommended number of entities in the DATA is 50 to 100.

{"STATE":"ERROR","ERROR":{"CODE":"ERR_API_TOO_MANY_DATA_ENTITIES","MESSAGE":""}}

API Response

These are some of the responses that may be returned by the PamBill API. These errors allow for handling of failures and provide the ability to have user interaction on them.

Please note that the response DATA can be an object, or an array of objects, or an empty array, depending on the response structure, which, in turn, depends on the request ACTION value.

Response STATE: OK

State OK means that the request JSON was parsed, the request passed the validation, the TOKEN was recognized, the ACTION was found, the CHECKSUM is correct, and the DATA could be parsed.

If some or all of the orders are rejected as duplicates, the response state will still be OK.

When an order is imported, the UUID will be returned in the response. Please save it, as the UUID can be used to reference the order in PamBill.

Orders imported

All orders have been successfully imported. The response includes the UUID of each order in PamBill.

{"STATE":"OK","DATA":{"SUCCESS":{"COUNT":2,"DATA":[{"order_number":1001,"uuid":"669b7d9Ga3p1ZF9F"},{"order_number":1002,"uuid":"4t2DD412EY8Cac9M"}]},"ERROR":{"COUNT":0,"DATA":[]}}}

Some of the orders rejected as duplicates

When some or all of the orders are rejected, they are listed in the ERROR section of the response DATA field.

{"STATE":"OK","DATA":{"SUCCESS":{"COUNT":1,"DATA":[{"order_number":1002,"uuid":"ZIe8CD3FMU1143zn"}]},"ERROR":{"COUNT":1,"DATA":[{"order_number":1001,"error":"ERR_INVOICE_ALREADY_EXISTS"}]}}}

Response STATE: ERROR

State ERROR means the request was rejected because it could not be parsed (invalid JSON), failed to pass the validation, authorization, or met one of the API limits.

Please do not rely on the MESSAGE field of the response. It is optional, and can be changed, translated or removed with time.

Order failed to parse

An order could not be imported. This usually means that some of the mandatory order fields are missing or have incorrect values.

Note that all other orders in the API request are rejected, too, as the request is considered malformed.

{"STATE":"ERROR","ERROR":{"CODE":"ERR_API_INCORRECT_DATA_FORMAT","MESSAGE":"order_number cannot be empty"}}

Other error messages

Below are more examples of the API responses in case of an error.

{"STATE":"ERROR","ERROR":{"CODE":"ERR_API_FAILED_TO_DECODE_JSON","MESSAGE":"Syntax error"}}

{"STATE":"ERROR","ERROR":{"CODE":"ERR_API_TOO_MANY_REQUESTS","MESSAGE":""}}

{"STATE":"ERROR","ERROR":{"CODE":"ERR_API_REQUEST_TOO_BIG","MESSAGE":"65536kB max"}}

{"STATE":"ERROR","ERROR":{"CODE":"ERR_API_TOO_MANY_DATA_ENTITIES","MESSAGE":""}}

{"STATE":"ERROR","ERROR":{"CODE":"ERR_API_DUPLICATED_REQUEST","MESSAGE":"CALL_ID must be unique for each request"}}

{"STATE":"ERROR","ERROR":{"CODE":"ERR_API_CHECKSUM_INCORRECT","MESSAGE":""}}

{"STATE":"ERROR","ERROR":{"CODE":"ERR_API_PRO_USERS_ONLY","MESSAGE":"You need to have an active Professional package to use the API. You can upgrade or convert your current package to Pro at https:\/\/www.pambill.com\/shop\/extend\/"}}

{"STATE":"ERROR","ERROR":{"CODE":"ERR_API_ACTION_NOT_SUPPORTED","MESSAGE":"Supported ACTION values are: import, import_shopify, validate_token, validate_account, pambill_package, latest_order_number"}}

API request samples

These sample requests can be sent to the PamBill API at https://pambill.com/api. Each of these requests will only succeed once, and will return ERR_API_DUPLICATED_REQUEST for all consequent attempts. That is because the API requires a unique CALL_ID for each call.

As the CALL_ID is used when calculating the CHECKSUM, it cannot be simply changed in the request. The CHECKSUM also needs to be updated. Changing the TOKEN value will also result in incorrect CHECKSUM, as each public token has a matching private (secret) token that needs to be used when calculating the checksum.

Full request JSON sample

{"VERSION": "1.2",
"ORIGIN": "WooCommerceApp",
"TOKEN": "Ii5haDTn40023KI9Y57a3aD77P1f9NG6",
"CALL_ID": "1661240906651DF892KQY9A969g2o15e",
"ACTION": "import",
"CHECKSUM": "6025eed28d1abc79f0c200c7d4ae7428e1a23469e1b56eede3333bd3fae3a5a8",
"DATA": [{
    "order_number": "1001",
    "order_date": "2024-12-23T11:00:00-05:00",
    "currency": "USD",
    "preferred_language": "en",
    "prices_include_vat": true,
    "payment": {
        "provider": "PayPal",
        "paid_at": null,
        "price_gross": null
    },
    "discount": {
       "price_gross": 10,
        "code": "Gift Voucher"
    },
   "refund": {
         "price_gross": 100,
        "cancelled_at": null,
        "reason": null
    },
    "billing_address": {
        "address1": "2259 Park Ct",
        "address2": "Apartment 5",
        "city": "Drayton Valley",
        "company": "Gorski & Partners",
        "company_vat": "DE250438265",
        "country_code": "CA",
        "email": "bob.norman@mail.example.com",
        "salutation": "Mr.",
        "first_name": "Christopher",
        "last_name": "Gorski",
        "name": "Christopher Gorski",
        "notes": null,
        "phone": "+13125551212",
        "region": "Alberta",
        "zip": "T0E 0M0"
    },
    "shipping_address": {
        "address1": "123 Amoebobacterieae St",
        "address2": "",
        "city": "Ottawa",
        "company": null,
        "country_code": "CA",
        "email": "bob.bobsen@mail.example.com",
        "salutation": null,
        "first_name": "Bob",
        "last_name": "Bobsen",
        "name": "Bob Bobsen",
        "notes": null,
        "phone": "555-625-1199",
        "region": "Ontario",
        "zip": "K2P0V6"
    },
    "items": [{
        "quantity": 1,
        "price_gross": "199.99",
        "sku": "IPOD-342-N",
        "name": "IPod Nano",
        "variant": "Pink",
        "apply_reduced_vat": false,
        "apply_no_vat": false,
        "special_vat_rate": null
    },
    {
        "quantity": 2,
        "price_gross": "15",
        "sku": "CASE-01",
        "name": "Universal Phone Case",
        "variant": null,
        "apply_reduced_vat": false,
        "apply_no_vat": false,
        "special_vat_rate": null
    },
    {
        "quantity": 1,
        "price_gross": "9.99",
        "sku": null,
        "name": "100% Arabica",
        "variant": "500g",
        "apply_reduced_vat": true,
        "apply_no_vat": false,
        "special_vat_rate": null
    },
    {
        "quantity": 1,
        "price_gross": "21.29",
        "sku": null,
        "name": "Bio Espresso Decaf",
        "variant": "1000g",
        "apply_reduced_vat": false,
        "apply_no_vat": false,
        "special_vat_rate": "3.7"
    },
    {
        "quantity": 1,
        "price_gross": "10.00",
        "sku": null,
        "name": "Something VAT-exempt",
        "variant": null,
        "apply_reduced_vat": false,
        "apply_no_vat": true,
        "special_vat_rate": null
    }],
    "shipping": {
        "delivery": {
            "price_gross": "9.99",
            "type": null
        },
        "post_fee": {
            "price_gross": null,
            "type": null
        }
    }
}]
}

Sending the request using cURL

curl -i -X POST -H 'Content-Type: application/json' -d '{"VERSION":"1.2","ORIGIN":"WooCommerceApp","TOKEN":"Ii5haDTn40023KI9Y57a3aD77P1f9NG6","CALL_ID":"1661240906651DF892KQY9A969g2o15e","ACTION":"import","CHECKSUM":"6025eed28d1abc79f0c200c7d4ae7428e1a23469e1b56eede3333bd3fae3a5a8","DATA":[{"order_number":"1001","order_date":"2024-12-23T11:00:00-05:00","currency":"USD","preferred_language":"en","prices_include_vat":true,"payment":{"provider":"PayPal","paid_at":null,"price_gross":null},"discount":{"price_gross":10,"code":"Gift Voucher"},"refund":{"price_gross":100,"cancelled_at":null,"reason":null},"billing_address":{"address1":"2259 Park Ct","address2":"Apartment 5","city":"Drayton Valley","company":"Gorski & Partners","company_vat":"DE250438265","country_code":"CA","email":"bob.norman@mail.example.com","salutation":"Mr.","first_name":"Christopher","last_name":"Gorski","name":"Christopher Gorski","notes":null,"phone":"+13125551212","region":"Alberta","zip":"T0E 0M0"},"shipping_address":{"address1":"123 Amoebobacterieae St","address2":"","city":"Ottawa","company":null,"country_code":"CA","email":"bob.bobsen@mail.example.com","salutation":null,"first_name":"Bob","last_name":"Bobsen","name":"Bob Bobsen","notes":null,"phone":"555-625-1199","region":"Ontario","zip":"K2P0V6"},"items":[{"quantity":1,"price_gross":"199.99","sku":"IPOD-342-N","name":"IPod Nano","variant":"Pink","apply_reduced_vat":false,"apply_no_vat":false,"special_vat_rate":null},{"quantity":2,"price_gross":"15","sku":"CASE-01","name":"Universal Phone Case","variant":null,"apply_reduced_vat":false,"apply_no_vat":false,"special_vat_rate":null},{"quantity":1,"price_gross":"9.99","sku":null,"name":"100% Arabica","variant":"500g","apply_reduced_vat":true,"apply_no_vat":false,"special_vat_rate":null},{"quantity":1,"price_gross":"21.29","sku":null,"name":"Bio Espresso Decaf","variant":"1000g","apply_reduced_vat":false,"apply_no_vat":false,"special_vat_rate":"3.7"},{"quantity":1,"price_gross":"10.00","sku":null,"name":"Something VAT-exempt","variant":null,"apply_reduced_vat":false,"apply_no_vat":true,"special_vat_rate":null}],"shipping":{"delivery":{"price_gross":"9.99","type":null},"post_fee":{"price_gross":null,"type":null}}}]}' https://www.pambill.com/api