Wednesday, 21 October, 2020

  • 3
  • 25,169

Xero API integration with PHP Laravel

It's hard to find complete guide on internet because the flow is not fully explained. Xero itself has a page to describe about how the flow should work but I missed it and have to keep testing to make it work.




Before we begin, you need to understand that Xero API is not as simple as other software API. It requires authorization and connection to be made before you can get the info even if you already have the client ID and secret key.



First, you need XeroAPI PHP OAuth library. If you are using Laravel, you should already have your composer set up, so you can run this



composer require xeroapi/xero-php-oauth2



Then, go to https://developer.xero.com/ and click My Apps. Login your account and click "New App" button. Fill in all necessary field like "App Name", "Company and application URL", "OAuth 2.0 redirect URI". (You can add up to 3 for OAuth 2.0 Redirect URI)

Generate secret key. Then copy the client ID and secret key into your your code.


Before you start with anything, remember to use all the classes in your Laravel controller first


use XeroAPI\XeroPHP\Configuration;
use XeroAPI\XeroPHP\Api\IdentityApi;
use GuzzleHttp\Client;
use XeroAPI\XeroPHP\Api\AccountingApi;


Then in your function, you can put these code

$clientId = 'YOUR_CLIENT_KEY';
$clientSecret = 'YOUR_SECRET_KEY';
$redirectUri = 'YOUR_REDIRECT_URI'; //Must be one of OAuth 2.0 redirect URI
$provider = new \League\OAuth2\Client\Provider\GenericProvider([
    'clientId'                => $clientId,   
    'clientSecret'            => $clientSecret,
    'redirectUri'             => $redirectUri,
    'urlAuthorize'            => 'https://login.xero.com/identity/connect/authorize',
    'urlAccessToken'          => 'https://identity.xero.com/connect/token',
    'urlResourceOwnerDetails' => 'https://api.xero.com/api.xro/2.0/Organisation'
]);

This is how your first part of code should look like. You can place this code anywhere in your function where you want it to be triggered. For example, a button to "Sync Xero Invoice" that will go to url "yourdomain.com/sync-invoice".


Your next part of code in the function should look something like this


if (!isset($_GET['code'])) {
    $options = [
        'scope' => ['openid email profile offline_access assets projects accounting.settings accounting.transactions accounting.contacts accounting.journals.read accounting.reports.read accounting.attachments']
    ];

    // Fetch the authorization URL from the provider; this returns the urlAuthorize option and generates and applies any necessary parameters (e.g. state).
    $authorizationUrl = $provider->getAuthorizationUrl($options);

    // Get the state generated for you and store it to the session.
    $_SESSION['oauth2state'] = $provider->getState();

    // Redirect the user to the authorization URL.
    header('Location: ' . $authorizationUrl);
    exit();

}


This part of code is the first process which is authorization request. It will redirect you to Xero login page. Enter your credential and click login, after you login, you will be redirected back to the "$redirectUri" you specified. They will pass back a GET parameter called code.  


So based on the image above, your next thing to do is to get access token.


$accessToken = $provider->getAccessToken('authorization_code', [
    'code' => $_GET['code']
]);


This will allow you to get the access token. Now for the 3rd process, you will need to get the tenant ID using the access token.



$config = Configuration::getDefaultConfiguration()->setAccessToken((string)$accessToken->getToken());
$identityInstance = new IdentityApi(new Client(), $config);

// Get Array of Tenant Ids
$result = $identityInstance->getConnections();

$tenantId = $result[0]->getTenantId(); //Tenant 1
$tenantId = $result[1]->getTenantId(); //Tenant 2
//And so on, depends on how many tenant you have. If you only have 1, use the $result[0]


Now it's all set. You have all the variables needed for the process that you want to do which is to get the protected resources. Let say you want to get invoices, you can setup AccountAPI and call the function getInvoices



$accountingApi = new AccountingApi(new Client(), $config);

$data = $accountingApi->getInvoices($tenantId);

foreach ($data->getInvoices() as $eachInvoice) {
    //Do what you need here
}


So it's all done. Do note if you use getInvoices without passing in any other condition, it will return compacted summary of invoices that doesn't have a line item. My suggestion is, you filter it with some condition or add pagination, then you will get the line item too. You can straight check the AccountApi class and see the getInvoices function to see what parameter they accept.


Few notes
- The authorization code can only be used for once. But in that one time, you can make multiple API call to Xero. So it's all up to you how you want to use it.
- If you are doing testing on localhost, you can put the $redirectUri to any website you owned. Then when you got redirected to Xero and login, it will redirect you to the $redirectUri. Copy the GET parameter "code" to your source code and hardcode it. Then comment out the code to get the authorization code (the if ($isset($_GET['code'])) section) and it will not redirect you to Xero login page, but will straight use the authorization code instead to get the access token.


Hope this helps. Any question, you can ask below.