Skip to content

Integrations and API keys

An API key lets another system (a website, a reporting tool, an HR app) read or write some of your company's data, server to server, without anyone signing in. A webhook goes the other way: Easy calls an address of yours when something happens. You make a key when a developer or a supplier asks for one, and you review the list now and then. The Owner or an Administrator does it. It goes with People, roles and access and Approvals and controls, because a key is a way into the books that has no person behind it.

About the screenshots

Screenshots are from Easy's demo company, Little Polynesian Café, running on a local computer, so the Base URL shows http://127.0.0.1:5054. A live company shows its own address. The key, Manual: reporting tool, is a made-up example that was revoked after the pictures. Its secret is painted over and is not written anywhere in this manual. No webhook address was added: Easy sends only to a public https:// address, and a real delivery would leave the machine, so that part is described from Easy's Help and source and flagged where it is.

Before you start

  • The REST API is a module. The pages below are behind it. In the demo it is on. If it is off for your company, these pages are gated under the name "The REST API" (from Easy's source; not shown in the demo). A company on Easy Payroll answers only the payroll, ledger-reading and PAYE/CINSF endpoints, whatever scopes a key has (Help).
  • Only an Owner or an Administrator opens these pages. A key can never act with more reach than the person who makes it (Help and source: the Acts as list offers only roles you may grant).
  • Know what the system needs, and nothing more. Give a key the smallest set of scopes that does the job. A reporting tool needs read; it should never hold write.
  • Plan who holds the token. It is shown once. Whoever has it can do what the key may do until you revoke it.

Step 1. Open Integrations

Settings → Integrations → Integrations.

Integrations: the base URL, how to send the key, and where the reference is

The Connect card gives what the other system needs: the Base URL, the header to send on every request (Authorization: Bearer em_live_<your-token>), and the fact that endpoints live under /api/v1. The Webhooks tab beside it is step 7. Below are Keys (none in a fresh company: "No API keys yet") and New key.

Step 2. Make a key

New key: a name, the scopes it may use, the role it acts as, read-only and an expiry date

Field What to do
Name The system that will use it ("Shop website", "Reporting tool"). It is how you tell keys apart later. Easy refuses a key with no name ("Give the key a name.", from its source)
What it may do Tick the scopes, grouped by area. Each says what it does in a line. Easy refuses a key with none ("Choose at least one scope.", from its source)
Acts as The role the key works as. It never gets more than that role: the demo offered Owner, Administrator, Accountant, Data Entry and Read Only / Auditor
Read-only "Ignore the role's write ability." Tick it for anything that only reports
Expires Starts one year ahead. Clear the date for a key that never expires: your choice, and a forgotten key then stays live for ever

The scopes, as the screen lists them:

Area Scopes
Sales sales:read (list and fetch invoices), sales:write (create and send invoices)
Credits and refunds credits:write (apply a credit note, or take that back), sales:refund (pay a credit note back to a customer: money leaves the bank)
Payments payments:read, payments:write (record a customer's payment against an invoice: money arrives in a bank account)
Banking banking:read (balances, payments made, transfers: nothing can be moved)
Customers contacts:read, contacts:write (add and change customers, add suppliers)
Items items:read (needs the Items add-on)
Tax payments tax:read, tax:write (record payments and refunds to RMD and CINSF)
Ledger and reports ledger:read (chart of accounts, reports, journals), ledger:write (post manual journals: the lock date and journal approval still apply)
Purchases purchases:read, purchases:write (enter supplier bills: a bill that needs approval is saved and waits for a person in Easy)
Payroll payroll:read (employees without bank or tax details, and pay runs with payslip totals)

The scopes are separate on purpose, so a key that only raises invoices cannot mark them paid, apply a credit or refund one. In the picture the key has two ticked: Sales read and Ledger and reports read, acting as Read Only / Auditor with Read-only ticked. The rest of the rules are in Scopes. Per Help, a ledger:write journal obeys the lock date and mandatory dimensions, and a bill or journal that your approval policy wants approved is saved and answered with status 202, then posts once a person approves it in Easy.

Choose Create key.

Step 3. Copy the token

The token is shown once: copy it now

A green box says Copy this token now. It is shown only once. Store it somewhere safe: Easy keeps only a hash. (The token itself is painted over here.) Copy it into the other system's settings, or a password manager, before you leave the page.

There is no way to see the token again

Easy stores only a hash. If the token is lost or has been shown to someone it should not have been, revoke the key and make a new one (step 6). Never email a token, paste it into a chat, or put it in a file that is kept in version control. Treat it as you would a bank password.

Step 4. Try the key

Check that the key does exactly what you meant. Three read-only calls to the demo's own API with this key show it:

curl -H "Authorization: Bearer em_live_<your-token>" "https://<your-easy-address>/api/v1/invoices?pageSize=1"
Request Answer Why
GET /api/v1/invoices with the key 200 The key holds sales:read
GET /api/v1/employees with the key 403, code insufficient_scope It does not hold payroll:read
GET /api/v1/invoices with no key 401, code unauthorized A request needs a key

Every refusal has the same shape: a status, a title, a detail and a stable code to test for. The others, from Help: not_found (404), validation_failed (422), period_locked (409, the date is in a closed period), company_read_only (403), not_in_plan (403) and rate_limited (429). More: Errors.

Step 5. Check on your keys

The key list: live, what it may do, who it acts as, and when it was last used

Each key shows its name, whether it is Live, Expired or Revoked, the start of its token (so you can tell which key a system holds without the secret), the scopes it holds, who it acts as, when it was created, when it was last used and when it expires. After a call, Last used changes from Never used to the time of the call. A key nobody has used for months, or one used by a system you no longer run, is a key to revoke. Working keys are listed first, newest first; revoked and expired ones sink below as history.

Step 6. Revoke a key

Choose Revoke on the key.

Revoke this API key? Anything using it stops working straight away

Easy asks: "Anything using it stops working straight away, and a revoked key can't be turned back on." Choose Revoke key (or Keep it).

A revoked key stays in the list, greyed, with the date

It now reads Revoked with the date, and it stays as history: the screen offers no delete and no way to switch it back on. A call with the revoked key now answers 401. If the system still needs access, make a new key and update it there. Do this at once if a token may have been seen by someone else, when the person who built the integration leaves, and when you stop using the system.

Step 7. Webhooks: Easy calls your system

Settings → Integrations → Webhooks.

Webhooks: no addresses yet, and the form to add one

A webhook is an address of yours that Easy calls when something happens, so your system hears about it instead of asking again and again. Not shown in the demo: a webhook working (see the note at the top). What follows is from Easy's Help and the page's own wording.

  • Add an address: a Name, an Address that starts with https:// and can be reached from the internet, and the Events it wants. The four are invoice.posted, invoice.paid (both ticked to begin with), customer.created and bill.approved.
  • The signing secret is shown once when you add it, like a token. You can make a new one at any time (New secret) and the old one stops working.
  • A delivery carries ids only: the event, the time, your company id and the ids of the record concerned. No names, amounts or bank details: your system reads the record through the API with its own key. That keeps personal data out of a request sent to an address Easy does not control.
  • Each delivery is signed. The X-EasyMoni-Signature header is t=<unix seconds>,v1=<hex>, an HMAC-SHA256 of <t>.<body> with the secret. Your system recomputes it over the raw body and refuses a delivery whose time is more than a few minutes old. X-EasyMoni-Delivery is the same on every retry of one event, so a repeat can be dropped.
  • If your system is down, Easy expects a 2xx answer within 10 seconds, tries again after 1 minute, 5 minutes, 30 minutes, 2 hours, 6 hours and 24 hours, then gives up. An address that fails 20 times in a row is switched Off with the reason shown, for you to fix and switch on.
  • Buttons on an address: Deliveries (what was sent and how each went), Send test (a ping event), Switch off / Switch on, New secret and Remove.
  • Refused addresses: only https:// on the standard port, with a host name (not an IP address), never one that resolves inside a private network, and Easy does not follow redirects.

More: Webhooks.

Limits, and sending the same request twice

From Easy's Help; not tried in the demo:

  • A company can have 25 live keys at most. Revoke one to make room.
  • Each key can make 60 requests a minute; past that the answer is 429 rate_limited with a Retry-After header.
  • On any request that creates or changes something, send an Idempotency-Key header (1 to 128 characters, no spaces, for example a UUID). If a request times out, send it again with the same key and content: Easy returns the original answer and does the work once, so a retry cannot create a second invoice or send a second email. Keys are kept for 24 hours and belong to the key that sent them (Retrying safely).

The reference

The Connect card links to an interactive reference at /api/docs. The same description in machine-readable form (OpenAPI) is at /openapi/v1.json. Not shown in the demo: the interactive reference page.

Other ways Easy connects outside

An API key is only one of them. The others have their own pages:

When something goes wrong

What you see What to do
The other system gets 401 unauthorized The token is missing, wrong, expired or revoked. Check the key's badge on the list and that the header is Authorization: Bearer …
403 insufficient_scope The key lacks the scope that call needs. The key list offers only Revoke, so make a new key that has it
403 company_read_only The company is view-only just now (from Help; not shown in the demo)
409 period_locked The date is in a closed period. Fix the date or have an accountant move the lock date
202 on a write Approval is on for that kind. The record waits for a person in Easy
429 rate_limited Slow down; wait the number of seconds in Retry-After
A webhook address is Off Read the reason under it, fix your system, then Switch on

Not shown in the demo, except 401 and 403 insufficient_scope: the rest are from Easy's Help.

Check before you continue

Check before you continue

  • Every key is named after the system that uses it, and holds only the scopes that system needs.
  • A key that only reports is ticked Read-only and acts as Read Only / Auditor.
  • Each token is stored somewhere safe, and nobody has been sent one in an email or a chat.
  • You tried the key (a call it should allow, and one it should refuse) before handing it over.
  • Keys nobody uses, and keys for people or systems that have gone, are revoked.
  • Any webhook address is https://, its signing secret is kept, and its deliveries are checked for the signature.