← the work

SERVICEM8 → XERO

Finished jobs that invoice themselves

A job's done in the field. The labour, the materials and the GST are already in ServiceM8 — so why is someone rebuilding the invoice by hand in Xero? Here's how we'd close that gap.

teardown · 5 min read · ServiceM8 API + Xero Accounting API

The problem

The team finishes a job, marks it complete in ServiceM8, and logs their hours and the materials they used. All the information needed to bill the customer now exists — accurately, from the people who did the work. Then, back at the office, someone opens Xero and builds that same invoice again from scratch.

That second pass is where money leaks. A bag of fittings that doesn't make it onto the invoice. Half an hour of labour rounded away. A job that sits "to be invoiced" for three weeks because the office is flat out, so the cash comes in a month later than it should have.

You did the work. The slowest and least reliable step shouldn't be getting paid for it.

"But doesn't ServiceM8 already sync to Xero?"

It does — and if the built-in sync fits how you work, you should use it. We'll tell you that on the fit call rather than sell you something you don't need.

Where a custom build earns its keep is when your billing has rules the native sync can't express. For example:

What "fixed" looks like

A job is marked complete. Within moments, a draft invoice appears in Xero with the labour costed from the actual hours logged, every material line carried across at your sell price, GST applied, and the income tagged to the right crew and account. The office reviews and sends — or it sends automatically, if you trust it to. Cash starts moving the day the work finishes, not the week someone gets to it.

How we'd connect it

We watch for a job reaching "Completed", pull the full picture of that job from the ServiceM8 API — the client, the labour activities, the materials — assemble it into an invoice under your rules, and create it in Xero.

Job completed pull labour + materials apply your billing rules Xero invoice

Pull the job's real costs

ServiceM8 keeps labour as job activities (time entries) and parts as job materials. We fetch both for the completed job and turn them into priced line items — labour at your charge-out rate, materials at their sell price.

build-lines.js
const api = "https://api.servicem8.com/api_1.0";

async function buildLines(jobUuid, chargeRate){
  const [materials, activities] = await Promise.all([
    get(`/jobmaterial.json?$filter=job_uuid eq '`+jobUuid+`'`),
    get(`/jobactivity.json?$filter=job_uuid eq '`+jobUuid+`'`)
  ]);

  const materialLines = materials.map(m => ({
    Description: m.name,
    Quantity: Number(m.quantity),
    UnitAmount: Number(m.price),       // sell price, not cost
    AccountCode: "200", TaxType: "OUTPUT"
  }));

  const hours = activities.reduce((h, a) =>
    h + minutesBetween(a.start_date, a.end_date) / 60, 0);

  return [...materialLines, {
    Description: "Labour",
    Quantity: round(hours, 2),
    UnitAmount: chargeRate,
    AccountCode: "201", TaxType: "OUTPUT"   // separate labour code
  }];
}

From there we attach the ServiceM8 client to a Xero contact, set the tracking category for the crew that did the job, and create the invoice as a draft (or approved) via Xero's Accounting API.

The edge cases that bite

// where field work meets accounting
  • Invoicing a job twice. A job can bounce back to "in progress" and be completed again. We record the Xero invoice ID against the ServiceM8 job so re-completion never creates a second invoice.
  • Cost price vs sell price. Materials carry both. Bill the sell price; the cost is for your margins, not the customer's invoice — getting these crossed is a classic and expensive mistake.
  • Rounding labour honestly. Time entries are messy. We round to a rule you choose (nearest 15 minutes, say) and apply it consistently, rather than letting raw seconds make ugly invoices.
  • GST on labour and materials. Correct tax types per line so the BAS is clean.
  • Photos and the work order. Where it helps you get paid faster, we attach the ServiceM8 job PDF to the Xero invoice so the customer sees what they're paying for.
  • Half-finished data. If a job's marked complete with no materials and no time logged, we hold it and flag it rather than sending a $0 invoice — a person decides.

But ServiceM8 already syncs to Xero?

It does, and for a lot of trades the built-in connector is enough — turn it on first. It pushes a completed job across as an invoice. Where it stops is the billing logic that's specific to how you quote and charge: that's the part that decides whether the invoice is right or just close.

// where the line sits
the built-in ServiceM8 → Xero sync
  • Pushes a completed job to Xero as an invoice on a standard mapping
  • Carries the line items and totals ServiceM8 already holds
  • Fine when you bill straight off the job exactly as entered
  • One workflow, the way the platform decides to do it
where we get called in
  • Labour costed from logged hours, rounded to a rule you choose
  • Materials billed at sell price while cost stays for your margins
  • Held-and-flagged jobs instead of $0 invoices when data's half-entered
  • simPRO instead of ServiceM8, or rules the built-in sync just can't express

What it'd take for you

Because the value is in your billing rules, these builds usually sit in the $8k–$18k range — the spread depends on how much logic lives between "job done" and "invoice right". We map those rules with you on a fixed scope before writing a line of code, and you'd run it on real jobs in draft mode until you trust it.

Still rebuilding invoices the office already has?

tell us how you bill · 20-min fit call

Book a fit call