// SIMPLYBOOK API

SimplyBook addClient fails: “Value is required and can’t be empty”

The error names no field, the documentation says the cause is impossible, and every obvious fix misses. Here is what is actually happening — and the undocumented parameter that fixes it.

  • ● Error -32070
  • ● Undocumented fix
  • ● Verified live

The symptom

You have a working SimplyBook admin token. Your JSON-RPC calls to https://user-api.simplybook.me/admin/ are authenticating cleanly. Then you call addClient with a perfectly sensible client object — name, email, phone — and get back this:

Value is required and can't be empty

No field name. No hint. The same message appears whatever you send. You add an address. Same error. You add a country id. Same error. You strip it back to just a name. Same error. We spent an afternoon on this while building our own booking system in July 2026, and the frustrating part is that the API already knows exactly which field is missing — it just doesn’t put it in the message.

Why the message is so unhelpful

The string you see is the top-level error.message of the JSON-RPC envelope. It is a generic validation message, reused for every required-field failure across the API. Most HTTP clients, most logging setups and most thin JSON-RPC wrappers surface error.message and stop there. So the one useful piece of information — which field — never reaches your eyes. The bug isn’t really in SimplyBook; it’s in the layer between you and it.

The false trails

getCompanyParam('require_fields')

This looks like the answer and isn’t. It returns which built-in fields your company requires. On our account it returned email — which we were already sending. It tells you nothing about custom client fields, so a clean pass here can leave you convinced the problem must be elsewhere.

Mandatory registration fields

In SimplyBook admin, Settings → Email and SMS settings has a “Mandatory registration fields” option. That genuinely can block API client creation, so it is worth checking. But it wasn’t our cause, and turning it off didn’t change the error.

The documentation saying custom fields have no API

This is the trail that costs you the most time. SimplyBook’s documentation for the company administration service lists addClient as accepting only name, email, phone, address1, address2, city, zip and country_id, and states that custom Client Fields have no API surface. Read literally, that means a required custom field makes API client creation impossible and your only option is to disable the field in admin. That is wrong. The live API accepts custom fields perfectly well.

The breakthrough: error code −32070

Print the whole error object rather than the message, and the picture changes. The failure comes back as JSON-RPC error code -32070, and its data member carries a field key naming the exact culprit:

{
  "error": {
    "code": -32070,
    "message": "Value is required and can't be empty",
    "data": { "field": "client_fields/9f7e5581a1b24c0e8d3f6b27c4e01a5d" }
  }
}

That 32-character hex string is the internal id of a custom Client Field on your account (Custom Features → Client Fields; on newer accounts the screen is called “Intake form for clients”). The API has been telling you the answer the whole time.

The shape that works

Supply a client_fields map, keyed by those ids, inside the client-data object you pass to addClient. Despite the documentation, it is accepted:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "addClient",
  "params": [
    {
      "name":  "Jane Smith",
      "email": "jane@example.com",
      "phone": "07700 900123",
      "client_fields": {
        "9f7e5581a1b24c0e8d3f6b27c4e01a5d": "Bournemouth"
      }
    }
  ]
}

We verified this live with a dry-run create that auto-filled one required custom field: the call that had failed indefinitely succeeded on the first attempt once the map was present.

The reusable technique: attempt, read, fill, retry

Because you can’t enumerate the fields from the docs, treat the error as a discovery channel. The loop is small and it is the part worth stealing:

  1. Call addClient with what you have.
  2. If it succeeds, you’re done.
  3. If the error code is -32070 and data.field matches client_fields/<id>, extract the id.
  4. Add that id to your client_fields map with a sensible value — a real answer if you have one, otherwise a neutral placeholder your staff will recognise.
  5. Retry. Repeat for each newly named field, with a hard cap (we use five) so a field that refuses every value can’t spin forever.
  6. Log the ids you discovered, along with any value you had to invent, so a human can review them later.
$fields = [];
for ($attempt = 0; $attempt < 5; $attempt++) {
    $res = $api->addClient($client + ['client_fields' => $fields]);
    if (!isset($res['error'])) { return $res; }

    $err = $res['error'];
    if (($err['code'] ?? null) !== -32070) { throw new Exception($err['message']); }

    $named = $err['data']['field'] ?? '';
    if (strpos($named, 'client_fields/') !== 0) { throw new Exception($err['message']); }

    $id = substr($named, strlen('client_fields/'));
    if (isset($fields[$id])) { throw new Exception('Field ' . $id . ' rejected our value'); }
    $fields[$id] = $this->valueFor($id);   // real answer, else a recognisable placeholder
}

Fill one field per round rather than guessing several at once. The API names them one at a time, and a loop that respects that stays honest about what it actually learned.

Never truncate an error payload

The reason this knowledge is so hard to find is mundane: error.data is routinely thrown away. Client libraries map JSON-RPC faults onto exceptions carrying only code and message. Log formatters cap strings at 200 characters. Error trackers store the message and drop the structured extras. Any one of those is enough to hide the field name forever. When you integrate with an unfamiliar JSON-RPC API, log the entire error object verbatim before anything else touches it — and if your wrapper doesn’t expose data, replace the wrapper.

The ids are per-account, so discover them at runtime

Those 32-hex ids belong to your company’s configuration, not to SimplyBook globally. Hard-coding the one you found in development will break the moment you point at a different account — a client’s, a staging company, or your own after someone edits the intake form. Keep the discovery loop in production, cache what it finds per account, and let it re-learn if a new field appears. That way an admin adding a required question to the intake form is a logged event rather than a silent outage.

We worked this out building our own booking system, where SimplyBook.me is only the diary engine behind a PHP proxy and customers never see it. If you are wrestling with the same integration, or want something similar built properly for your business, 365 Techies can help.

// GOOD QUESTIONS

Frequently asked

Why does the error not say which field?

It does — but not in the message. The JSON-RPC error object carries data.field naming the exact field as client_fields/<id>. Most logging and many client libraries print only error.message and discard error.data, which is why the answer stays hidden.

The docs say custom client fields have no API. Are they wrong?

On this point, yes. The documented field list for addClient omits custom fields entirely, yet supplying a client_fields map keyed by the ids from the error payload works. We verified it against a live account.

Can I hard-code the field ids?

Don’t. They’re per-account 32-character identifiers, so an integration that hard-codes them breaks on the next account. Discover them at runtime from the error and fill what you’re told to fill.

Is unticking “required” in the admin an alternative?

It is, if you can find the setting and don’t need the field enforced elsewhere. On newer accounts the screen is called “Intake form for clients” rather than “Client Fields”, which is one reason people struggle to locate it. Handling it in code is more robust because it survives someone re-ticking the box.

Thinking about your own booking experience?

We built ours on SimplyBook and it is live on this site — have a look, then tell us what you are trying to do. Quoted per project, honestly, after a proper look.

01202 775566 · help@365techies.co.uk · MON–FRI 9AM–5PM