Connect the bexio API to WordPress

An enquiry from the website form should arrive in bexio as a contact, an order as an invoice, a shop customer as an address. For that, WordPress has to talk to the bexio API. This guide walks from the app in the Developer Portal to the first contact created, the pitfalls along the way, and when a ready-made plugin is worth more than your own code.

How it works: the website form sends the enquiry to WordPress, WordPress gets a token from auth.bexio.com and creates contact and note through api.bexio.comWebsite formA visitor sendsan enquiryWordPressPlugin or owncode with atokenauth.bexio.comToken via OAuth2, refreshedregularlyapi.bexio.comFind or createthe contact,add a noteHow it works: the website form sends the enquiry to WordPress, WordPress gets a token from auth.bexio.com and creates contact and note through api.bexio.comWebsite formA visitor sends an enquiryWordPressPlugin or own code with a tokenauth.bexio.comToken via OAuth 2, refreshed regularlyapi.bexio.comFind or create the contact, add a note

What the bexio API is

The bexio API is a REST interface using JSON. All endpoints live under https://api.bexio.com, and depending on the area the paths start with /2.0/, /3.0/ or newer, for example /2.0/contact for contacts and /3.0/users/me for the signed-in user. The reference is at docs.bexio.com. According to its own documentation, bexio offers no OpenAPI description, so a client is written by hand.

Every request needs an access token in the Authorization: Bearer … header. How WordPress gets that token is the real work.

Step 1: create an app in the Developer Portal

  1. Sign in to the Developer Portal with the bexio account.
  2. Read and accept the terms of use, especially section 4.4 on commercial use (see pitfalls).
  3. Create a new app and enter the redirect URL bexio sends the user back to after signing in, for example the plugin's settings page in the WordPress admin. Up to ten addresses are possible, for instance for test and production.
  4. Read the Client ID and Client Secret under "App Details".

The Client Secret stays on the server, never in JavaScript in the browser.

Step 2: sign in with OAuth 2

bexio signs in through OpenID Connect on auth.bexio.com, using the "Authorization Code Flow". WordPress sends the user to the bexio sign-in page:

https://auth.bexio.com/realms/bexio/protocol/openid-connect/auth
  ?client_id=<Client ID>
  &redirect_uri=<registered redirect URL>
  &response_type=code
  &scope=openid offline_access contact_edit note_edit
  &state=<random value>

The user signs in and confirms the permissions. bexio redirects back with a code, which WordPress exchanges, together with Client ID and Secret, at the token endpoint /realms/bexio/protocol/openid-connect/token for an access token and a refresh token.

About scopes: a write permission includes read access, so contact_edit is enough for searching too. offline_access is needed for the refresh token. And the API always works with the permissions of the user who set up the connection: if that user cannot see contacts in bexio, neither can the app.

Step 3: store and refresh tokens

The access token expires quickly. Before it does, WordPress gets a new one with the refresh token and grant_type=refresh_token, all values in the request body, not in the URL. Keep in mind:

  • Always store the new refresh token returned by the refresh.
  • If a connection goes a year without a refresh, bexio closes the session; someone then has to sign in again.
  • Store tokens in WordPress options without autoload, so they are not loaded on every page view.

For your own scripts there are also personal access tokens (PAT). They have full access to all of the company's data and are valid for 60 days. Handy for personal use, they are not suitable for a plugin on a customer's website.

Step 4: create a contact and a note

A typical flow for a form enquiry needs four calls:

  1. GET /3.0/users/me returns the user's ID. It is required when creating, as user_id and owner_id.
  2. POST /2.0/contact/search checks by email address whether the contact already exists.
  3. If not: POST /2.0/contact creates it, contact_type_id 1 for companies, 2 for people.
  4. POST /2.0/note attaches the form text to the contact as a note.

The call to create a company looks like this:

{
  "contact_type_id": 1,
  "name_1": "Example Ltd",
  "street_name": "Bahnhofstrasse",
  "house_number": "1",
  "postcode": "8001",
  "city": "Zurich",
  "mail": "info@example.ch",
  "user_id": 1,
  "owner_id": 1
}

Common pitfalls

  • Redirect URL: it has to match the Developer Portal exactly, otherwise sign-in stops with an error message.
  • New scopes: a connection's permissions do not change on refresh. If the app needs more, the user has to sign in again.
  • Address fields: the address field is deprecated when creating. Street and house number go into street_name and house_number.
  • Line breaks in notes: bexio shows the text of a note without line breaks. For paragraphs, use <br> and escape the values as HTML.
  • Rate limit: too many requests per minute and the API answers with status 429. The headers RateLimit-Remaining and RateLimit-Reset tell you how long to wait.
  • Slow forms: calling bexio while the form is submitted keeps the visitor waiting and loses the enquiry if bexio does not respond. Better to transfer in the background and retry on errors.
  • Commercial use: under section 4.4 of the terms, anyone running a business model of their own on the API with at least five bexio accounts connected has to inform bexio.

Three approaches compared

ApproachFits whenKeep in mind
Build it yourselfyou have developers and the process is very specificsign-in, token refresh, error handling and updates stay your own work for good
Zapier or Makeother workflows already run thereone more service the form data passes through, mapping and duplicates by hand
Ready-made pluginthe process follows a common patternless freedom than your own code

Make and Zapier offer bexio as an app of its own. The form plugin sends the enquiry there by webhook, and a bexio action creates the contact.

Ready-made solutions

For the two most common cases there are my integrations:

  • bexio form connector: WordPress plugin, enquiries from the website form become contacts with a note in bexio, duplicates are recognised by email. Each site owner connects their bexio through their own app, and the data goes straight from the website to bexio.
  • bexio ↔ HubSpot: a won deal in HubSpot becomes a quote or invoice in bexio, and the payment status flows back into the deal.

All guides