Select Page

i 3 Table Of Content

Overview of Integration

Integration of Xero (used for accounting) and Salesforce CRM is required to automate several tasks. Simplification of creating and viewing Xero Customers and Invoices can be achieved by integrating the aforementioned apps. Even if the pre-built Salesforce Integration for Xero may not suffice for your company’s needs, a custom Apex can be created and a solution developed. Instruction on achieving this will be provided in this post!

Combining the two platforms requires admin access to Salesforce (Enterprise Edition or higher, or a Dev/Sandbox org for testing) and Xero. Additionally, prior knowledge of Apex coding is necessary. If Apex utilization is unfamiliar, consideration might be given to employing Zapier’s no-code integration or Breadwinner’s no-code interface with Salesforce.

Remote Site Settings

Registering the target site in the Remote Site Settings is necessary for a callout from Salesforce to an external website. Salesforce restricts calls to unregistered network addresses. If the site is not registered, the callout will not function.

Before calling Xero Endpoints, two remote site configurations must be created in Salesforce using below mentioned steps:

  1. Go to Setup.
  2. Type “Remote Site” into the Quick Find search bar.
  3. Then select “Remote Site Settings.”
  4. Make the following two remote site configurations, each with a distinct function.
    1. Use this URL to authenticate yourself and get the access token: https://identity.xero.com/
    2. Use this URL to carry out operations on data, including contacts, invoices, bills, and purchase orders: https://api.xero.com/
Create Remote Site Settings

Connecting to Xero using OAuth 2.0 Custom Connection

Navigate to “https://developer.xero.com” to create a Custom Connection App on Xero. Then, select “My Apps” and provide all the necessary information to develop the Custom Connection App. After completing the application configuration, you will receive your unique Client ID and Client Secret. Please note that your Client ID and Secret will appear different from those displayed.

Client ID: 8459AA********************5C8E0
Client Secret: 3hZBw*********************************895nPi

Create Xero Custom Connection

You can try out the codes that were generated above to get the access token by requesting the endpoint “https://identity.xero.com/connect/token.”

Please see the sample code provided below.

public class XeroAuth {
    public static string getAccessToken(){
        String clientId = '8459AAB84EAB44D9920C55129325C8E0';
        String clientSecret = '3hZBwUojX67IJRJKcdJnyz1N4wU_-A4FQEwob8pVgY895nPi';
        Blob headerValue = Blob.valueOf(clientId + ':' + clientSecret);
        String authorizationHeader = 'Basic ' + EncodingUtil.base64Encode(headerValue);
        String payload = 'grant_type=client_credentials&scope=accounting.transactions accounting.contacts';

        HttpRequest req = new HttpRequest();
     	req.setEndpoint('https://identity.xero.com/connect/token');
     	req.setMethod('POST');
        req.setHeader('Authorization', authorizationHeader);
        req.setHeader('Content-Type', 'application/x-www-form-urlencoded');
        req.setBody(payload);
        
        Http http = new Http();
     	HTTPResponse res = http.send(req);
        
        if(res.getStatusCode() != 200 && res.getBody() != NULL){
            String respBody = res.getBody();        
        	Map<String, Object> respMap = (Map<String, Object>)JSON.deserializeUntyped(respBody); 
		if(respMap.containsKey('access_token'))
            	return String.valueOf(respMap.get('access_token'));
        }
        
        return null;
        
    }
}

For any more requests, use the Access Token that was generated from that previously mentioned class. It has a validity of 1800 seconds.

Xero Contacts

Reading Contacts

To get the details of your Xero Contact(s), use the code below. You may also use the “IDs” option in the endpoint to retrieve specific Xero Contact information.

public class XeroContact {
	public static final String apiEndpoint = 'https://api.xero.com/api.xro/2.0/';
    
    public static String getAllXeroContacts(){
        String accessToken = XeroAuth.getAccessToken();
        system.debug(accessToken);
        
        if(accessToken != NULL){
            HttpRequest req = new HttpRequest();
            req.setEndpoint(apiEndpoint+'Contacts');
            req.setMethod('GET');
            req.setHeader('Authorization', 'Bearer '+accessToken);
            system.debug(req);
            
            Http http = new Http();
            HTTPResponse res = http.send(req);
            
            if(res.getStatusCode() == 200 && res.getBody() != NULL){
                String contactsJSONResponse = res.getBody();
                system.debug(contactsJSONResponse);
                return contactsJSONResponse;
            }
        }
        return null ;
    }
}

By providing the “IDs” option along with the code, you can obtain specific Xero contacts, as demonstrated by the URL below.

https://api.xero.com/api.xro/2.0/Contacts?IDs=220ddca8-3144-4085-9a88-2d72c5133734,88192a99-cbc5-4a66-bf1a-2f9fea2d36d0

Managing Xero Contacts – Creation and Update

Adhering to Xero API guidelines necessitates completing certain mandatory fields when creating a Xero Contact. Moreover, when upgrading a Xero Contact, it’s crucial to incorporate the “ContactID” in the request body.

The provided code can be employed to create or update a Xero contact based on the value of the “isCreate” option. If the “isCreate” argument is TRUE, the request method will be specified as PUT; otherwise, it will be configured as POST.

public class XeroContact {
    public static final String apiEndpoint = 'https://api.xero.com/api.xro/2.0/';
        
    public static String createUpdateXeroContact(Boolean isCreate){
        String accessToken = XeroAuth.getAccessToken();
        system.debug(accessToken);

		if(accessToken != NULL){
			String jsonBody = '{ "Contacts": [ { "Name": "Bruce Banner", "EmailAddress": "hulk@avengers.com", "Phones": [ { "PhoneType": "MOBILE", "PhoneNumber": "555-1212", "PhoneAreaCode": "415" } ], "PaymentTerms": { "Bills": { "Day": 15, "Type": "OFCURRENTMONTH" }, "Sales": { "Day": 10, "Type": "DAYSAFTERBILLMONTH" } } } ] }';

            HttpRequest req = new HttpRequest();
            req.setEndpoint(apiEndpoint+'Contacts');
            req.setMethod(isCreate ? 'PUT' : 'POST');
            req.setHeader('Authorization', 'Bearer '+accessToken);
            req.setHeader('Content-Type', 'application/json');
            req.setHeader('Accept', 'application/json');
            req.setBody(jsonBody);
            system.debug(req);
            
            Http http = new Http();
            HTTPResponse res = http.send(req);
            
            if(res.getStatusCode() == 200 && res.getBody() != NULL){
                String contactJSONResponse = res.getBody();
                system.debug(contactJSONResponse);
                return contactJSONResponse;
            }
        }
        return null ;
    }
}

Xero Invoices

Reading Invoices

To get the details of a Xero invoice(s) from Xero, use the code that is provided below. You may also use the “IDs” option in the endpoint to retrieve specific Xero Invoice data.

public class XeroInvoice {
	public static final String apiEndpoint = 'https://api.xero.com/api.xro/2.0/';
    
    public static String getAllXeroInvoices(){
        String accessToken = XeroAuth.getAccessToken();
        system.debug(accessToken);
        
        if(accessToken != NULL){
            HttpRequest req = new HttpRequest();
            req.setEndpoint(apiEndpoint+'Invoices');
            req.setMethod('GET');
            req.setHeader('Authorization', 'Bearer '+accessToken);
            system.debug(req);
            
            Http http = new Http();
            HTTPResponse res = http.send(req);
            
            if(res.getStatusCode() == 200 && res.getBody() != NULL){
                String invoicesJSONResponse = res.getBody();
                system.debug(invoicesJSONResponse);
                return invoicesJSONResponse;
            }
        }
        return null;
    }
}

With the given code and the “IDs” option, you can obtain specific Xero invoices, as the following API illustrates.

https://api.xero.com/api.xro/2.0/Invoices?IDs=fee88eea-f2aa-4a71-a372-33d6d83d3c45,9f5bca33-8590-4b6f-acfb-e85712b10217

Managing Xero Invoices – Creation and Update

In accordance with Xero API guidelines, a few required fields must be filled out when generating a Xero invoice. However, it is essential to include the “InvoiceID” in the request body when changing a Xero invoice.

Depending on the value of the “isCreate” option, the code below can be used to create or update a Xero invoice. The request method will be specified as PUT if the “isCreate” argument is set to TRUE; otherwise, it will be configured as POST.

public class XeroInvoice {
    public static final String apiEndpoint = 'https://api.xero.com/api.xro/2.0/';
        
    public static String createUpdateXeroInvoice(Boolean isCreate){
        String accessToken = XeroAuth.getAccessToken();
        system.debug(accessToken);

		if(accessToken != NULL){
			String jsonBody = '{ "Invoices": [ { "Type": "ACCREC", "Contact": { "ContactID": "430fa14a-f945-44d3-9f97-5df5e28441b8" }, "LineItems": [ { "Description": "Acme Tires", "Quantity": 2, "UnitAmount": 20, "AccountCode": "200", "TaxType": "NONE", "LineAmount": 40 } ], "Date": "2019-03-11", "DueDate": "2018-12-10", "Reference": "Website Design", "Status": "AUTHORISED" } ] }';

            HttpRequest req = new HttpRequest();
            req.setEndpoint(apiEndpoint+'Invoices');
            req.setMethod(isCreate ? 'PUT' : 'POST');
            req.setHeader('Authorization', 'Bearer '+accessToken);
            req.setHeader('Content-Type', 'application/json');
            req.setHeader('Accept', 'application/json');
            req.setBody(jsonBody);
            system.debug(req);
            
            Http http = new Http();
            HTTPResponse res = http.send(req);
            
            if(res.getStatusCode() == 200 && res.getBody() != NULL){
                String invoiceJSONResponse = res.getBody();
                system.debug(invoiceJSONResponse);
                return invoiceJSONResponse;
            }
        }
        return null ;
    }
}

Alternatives to a Custom Integration

Breadwinner’s Xero Salesforce Integration is an alternative option, if there are challenges in developing a customized Apex integration. It may be due to limitations such as the absence of LWC components or difficulties in managing updates and race conditions. This solution can aid in the rapid expansion and scaling of your organization, with clear and defined costs.

Alternatively, integration of Salesforce and Xero can be achieved using Workato or Zapier.