top of page
  • Gold-Service partner
  • LinkedIn

Building a Custom Connector to Xero in Power Platform

  • Writer: Sofia Ng
    Sofia Ng
  • May 28
  • 3 min read

I’ve recently been working on a small integration that turned out to be quite satisfying to put together, so I thought I’d share the process in case it’s useful to anyone facing a similar problem.

The setup: I needed to connect Microsoft’s Power Platform to Xero to pull in purchase orders and create bills automatically. Xero doesn’t have a native connector in Power Automate, which meant rolling up my sleeves and building a custom one.


A white sink pipe

Step 1: Swagger First

To get started, I created a Swagger (OpenAPI) definition that outlines the endpoints I needed:

  • Getting the current connection (to fetch the tenant ID)

  • Retrieving purchase orders using their ID

  • Creating bills in Xero

Here’s a base Swagger definition for Xero:

swagger: '2.0'
info:
 title: Default title
  description: ''
  version: '1.0'
host: api.xero.com
basePath: /
schemes:
  - https
consumes: []
produces: []
paths:
  /api.xro/2.0/Invoices:
    get:
      responses:
        default:
          description: default
          schema: {}
      summary: GetInvoice
      operationId: GetInvoice
     parameters:
       - name: Content-Type
          in: header
          required: false
          type: string
        - name: Accept
          in: header
          required: false
          type: string
        - name: xero-tenant-id
          in: header
          required: false
          type: string
    put:
      responses:
        default:
          description: default
          schema: {}
      summary: Bill Creation
      operationId: PutBill
      parameters:
        - name: Content-Type
          in: header
          required: false
          type: string
        - name: Accept
          in: header
          required: false
          type: string
        - name: xero-tenant-id
          in: header
          required: false
          type: string
        - name: body
          in: body
          required: false
          schema:
            type: object
            properties:
              Type:
                type: string
                description: Type
              Contact:
                type: object
                properties:
                  Name:
                    type: string
                    description: Name
                description: Contact
              Date:
                type: string
                description: Date
              DueDate:
                type: string
                description: DueDate
              LineItems:
                type: array
                items:
                  type: object
                  properties:
                    Description:
                      type: string
                      description: Description
                    Quantity:
                      type: integer
                      format: int32
                      description: Quantity
                    UnitAmount:
                      type: integer
                      format: int32
                      description: UnitAmount
                    AccountCode:
                      type: string
                      description: AccountCode
                description: LineItems
              Reference:
                type: string
                description: Reference
              Status:
                type: string
                description: Status
  /connections:
    get:
      responses:
        default:
          description: default
          schema:
            type: array
            items:
              type: object
              properties:
                id:
                  type: string
                  description: id
                authEventId:
                  type: string
                  description: authEventId
                tenantId:
                  type: string
                  description: tenantId
                tenantType:
                  type: string
                  description: tenantType
                tenantName:
                  type: string
                  description: tenantName
                createdDateUtc:
                  type: string
                  description: createdDateUtc
                updatedDateUtc:
                 type: string
                  description: updatedDateUtc
      summary: Get Connection
      operationId: GetConnection
      parameters: []
  /api.xro/2.0/PurchaseOrders: {}
  /api.xro/2.0/PurchaseOrders/{purchaseOrderId}:
    get:
      responses:
        default:
          description: default
          schema: {}
      summary: Purchase Order Get
      operationId: GetPurchaseOrder
      parameters:
        - name: purchaseOrderId
          in: path
          required: true
          type: string
        - name: xero-tenant-id
          in: header
          required: false
          type: string
definitions: {}
parameters: {}
responses: {}
securityDefinitions:
  oauth2-auth:
    type: oauth2
    flow: accessCode
    authorizationUrl: https://login.xero.com/identity/connect/authorize
    tokenUrl: https://identity.xero.com/connect/token
    scopes:
      offline_access email openid profile accounting.transactions accounting.contacts accounting.settings.read: >-
        offline_access email openid profile accounting.transactions
        accounting.contacts accounting.settings.read
security:

  - oauth2-auth:
      - >-
        offline_access email openid profile accounting.transactions
        accounting.contacts accounting.settings.read
tags: []

It’s worth noting that Xero uses OAuth 2.0, so a bit of setup is required in their developer portal to get your client ID and secret. Once that’s configured, you can use this definition to register your connector inside Power Platform.


Step 2: Building the Flow

Once the connector was in place, I moved into Power Automate to build the actual flow. At a high level, it looks like this:

  • A scheduled trigger kicks off the flow (Recurrence).

  • It uses the custom connector to fetch a list of connections (to get the tenantid).

  • For each one, it retrieves the corresponding Purchase Order.

  • It then creates a new draft bill in Xero using the data from the PO.


A Quick Note on Permissions

The connector needs access to scopes like accounting.transactions, accounting.contacts, and so on. These are configured in the Swagger file and will be part of the OAuth consent process.


Why Bother?

It’s easy to overlook small bits of automation like this, especially when you’re surrounded by big shiny platforms promising out-of-the-box magic. But this kind of targeted, custom integration is where Power Platform really shines—especially when you want to automate around systems like Xero that don’t always play natively with Microsoft tools.


If you’re exploring something similar or want help to get started, let us know. Happy to share notes or tweaks from what we’ve learned along the way.

Gold medal Make Partner

Contact Us

QUESTIONS?

WE'RE HERE TO HELP

  • LinkedIn

© 2023 by Ava Technology Solutions. Proudly created with Wix.com

bottom of page