Skip to content
Try For Free
Bizstim
Free tools
Pricing Contact Log in
Try For Free Book Demo
Home / API Reference
Developers

API Reference Your Bizstim data, from your own systems.

A JSON REST API for the clients, practitioners, staff, sessions, services and payments on your account. One key, one base URL, the same records you see in the app.

Getting started

The Bizstim API gives your own software access to the records on your account: read them today, with create, update and delete arriving one resource at a time. Every request is an HTTPS call to the base URL below with your API key in a header, and every reply is JSON.

BASE https://www.bizstim.com/api/v1

The API is included in the Enterprise plan and during the free trial. See the plans, or start a trial.

Your first request

Replace YOUR_API_KEY with a key from your account (the next section) and list two clients:

curl "https://www.bizstim.com/api/v1/clients?limit=2" \
  -H "X-API-KEY: YOUR_API_KEY" \
  -H "Accept: application/json"

The reply is a list envelope with the records in data:

{
    "object": "list",
    "total": 57,
    "limit": 2,
    "offset": 0,
    "has_more": true,
    "data": [
        {
            "object": "client",
            "id": 42,
            "first_name": "Jane",
            "last_name": "Doe",
            "address1": "12 Main Street",
            "address2": "Suite 4",
            "city": "Toronto",
            "state": "ON",
            "zipcode": "M5V 2T6",
            "country": "Canada",
            "p_phone": "416-555-0100",
            "s_phone": "416-555-0101",
            "text_phone": "416-555-0102",
            "dob": "1990-05-20",
            "status": "active",
            "inactive_date": "2026-01-15",
            "inactive_reason": "An example reason.",
            "start_date": "2026-01-15",
            "notes": "Prefers afternoon appointments.",
            "timezone": "America/Toronto",
            "send_welcome_message": 1,
            "send_lesson_reminders": 1,
            "add_session": 1,
            "see_practs_information": 1,
            "text_reminders": 1,
            "use_records": 1,
            "session_cancel": 1,
            "ace": 1,
            "hide_costs": 1,
            "username": "jane.doe",
            "email": "jane.doe@example.com"
        },
        {
            "object": "client",
            "id": 43,
            "first_name": "Jane",
            "last_name": "Doe",
            "address1": "12 Main Street",
            "address2": "Suite 4",
            "city": "Toronto",
            "state": "ON",
            "zipcode": "M5V 2T6",
            "country": "Canada",
            "p_phone": "416-555-0100",
            "s_phone": "416-555-0101",
            "text_phone": "416-555-0102",
            "dob": "1990-05-20",
            "status": "active",
            "inactive_date": "2026-01-15",
            "inactive_reason": "An example reason.",
            "start_date": "2026-01-15",
            "notes": "Prefers afternoon appointments.",
            "timezone": "America/Toronto",
            "send_welcome_message": 1,
            "send_lesson_reminders": 1,
            "add_session": 1,
            "see_practs_information": 1,
            "text_reminders": 1,
            "use_records": 1,
            "session_cancel": 1,
            "ace": 1,
            "hide_costs": 1,
            "username": "jane.doe",
            "email": "jane.doe@example.com"
        }
    ]
}

Authentication

Every request carries your key in the X-API-KEY header. A key belongs to one Bizstim account and only ever reads or changes that account's records.

Creating a key

Log in to Bizstim, open Settings, then System, and find API Settings. Generate API Key creates the account's primary key, which may use every resource. Add Secondary API Key creates a key limited to the resources you tick; a secondary key answers 403 resource_not_allowed on anything else.

  • Treat a key like a password: keep it on your server, never in a browser or a mobile app.
  • To rotate a key, delete it and generate a new one. The old key stops working at once.
  • A missing or unknown key answers 401 invalid_key.

Account gates

If the account's e-mail address is not verified, the subscription has lapsed, or the plan does not include the API, every request answers 403 with the matching code (see Errors). The message names the fix.

Making requests

Resources are plural nouns in the path; the HTTP verb says what to do.

RequestActionReply
GET /api/v1/clientsList200 with a list envelope
GET /api/v1/clients/{id}Retrieve200 with one record
POST /api/v1/clientsCreate201 with the new record
PATCH /api/v1/clients/{id}Update the fields you send (PUT is accepted as the same call)200 with the updated record
DELETE /api/v1/clients/{id}Delete200 with {"id", "object", "deleted": true}

Create, update and delete are being added one resource at a time. Each resource page lists exactly the endpoints that are live today; a verb a resource does not support answers 405 with an Allow header naming the ones it does.

  • Request bodies are JSON (Content-Type: application/json), 256 KB at most. Lookups and filters are query parameters. Filters combine: a record is returned only when it matches every filter you send. The key goes in the X-API-KEY header only, never in the URL.
  • Ids are integers. A record that does not exist on your account answers 404 not_found, including ids that belong to another account.
  • Length limits apply to the value as stored. The characters & < > " ' are stored as HTML entities (5 or 6 characters each), so a value that fits the limit as sent but not once stored answers 400 naming the field.
  • Paths use hyphens (/custom-fields); JSON fields use underscores (first_name).
  • Only JSON is returned. The format parameter of the retired API is ignored.

Responses

Every record carries object, the resource it belongs to, followed by the record's fields in a fixed order. Integers and decimals are JSON numbers, everything else is a string, and an empty value is null.

{
    "object": "client",
    "id": 42,
    "first_name": "Jane",
    "last_name": "Doe",
    "address1": "12 Main Street",
    "address2": "Suite 4",
    "city": "Toronto",
    "state": "ON",
    "zipcode": "M5V 2T6",
    "country": "Canada",
    "p_phone": "416-555-0100",
    "s_phone": "416-555-0101",
    "text_phone": "416-555-0102",
    "dob": "1990-05-20",
    "status": "active",
    "inactive_date": "2026-01-15",
    "inactive_reason": "An example reason.",
    "start_date": "2026-01-15",
    "notes": "Prefers afternoon appointments.",
    "timezone": "America/Toronto",
    "send_welcome_message": 1,
    "send_lesson_reminders": 1,
    "add_session": 1,
    "see_practs_information": 1,
    "text_reminders": 1,
    "use_records": 1,
    "session_cancel": 1,
    "ace": 1,
    "hide_costs": 1,
    "username": "jane.doe",
    "email": "jane.doe@example.com"
}
  • Dates are YYYY-MM-DD and times HH:MM:SS, in the account's time zone (sessions name it in their timezone field).
  • Each resource page lists the fields with their types. A field is never removed or renamed within v1; new fields may be added.

Pagination

Every list answers the same envelope. limit is the page size (1 to 1000, default 100) and offset the number of records to skip (default 0). total counts every record that matches the filters and has_more says whether another page exists.

{
    "object": "list",
    "total": 57,
    "limit": 2,
    "offset": 0,
    "has_more": true,
    "data": [
        {
            "object": "client",
            "id": 42,
            "first_name": "Jane",
            "last_name": "Doe",
            "address1": "12 Main Street",
            "address2": "Suite 4",
            "city": "Toronto",
            "state": "ON",
            "zipcode": "M5V 2T6",
            "country": "Canada",
            "p_phone": "416-555-0100",
            "s_phone": "416-555-0101",
            "text_phone": "416-555-0102",
            "dob": "1990-05-20",
            "status": "active",
            "inactive_date": "2026-01-15",
            "inactive_reason": "An example reason.",
            "start_date": "2026-01-15",
            "notes": "Prefers afternoon appointments.",
            "timezone": "America/Toronto",
            "send_welcome_message": 1,
            "send_lesson_reminders": 1,
            "add_session": 1,
            "see_practs_information": 1,
            "text_reminders": 1,
            "use_records": 1,
            "session_cancel": 1,
            "ace": 1,
            "hide_costs": 1,
            "username": "jane.doe",
            "email": "jane.doe@example.com"
        },
        {
            "object": "client",
            "id": 43,
            "first_name": "Jane",
            "last_name": "Doe",
            "address1": "12 Main Street",
            "address2": "Suite 4",
            "city": "Toronto",
            "state": "ON",
            "zipcode": "M5V 2T6",
            "country": "Canada",
            "p_phone": "416-555-0100",
            "s_phone": "416-555-0101",
            "text_phone": "416-555-0102",
            "dob": "1990-05-20",
            "status": "active",
            "inactive_date": "2026-01-15",
            "inactive_reason": "An example reason.",
            "start_date": "2026-01-15",
            "notes": "Prefers afternoon appointments.",
            "timezone": "America/Toronto",
            "send_welcome_message": 1,
            "send_lesson_reminders": 1,
            "add_session": 1,
            "see_practs_information": 1,
            "text_reminders": 1,
            "use_records": 1,
            "session_cancel": 1,
            "ace": 1,
            "hide_costs": 1,
            "username": "jane.doe",
            "email": "jane.doe@example.com"
        }
    ]
}

To read everything, repeat the request with offset increased by limit until has_more is false. Lists are ordered by id, oldest first, so a new record appears at the end.

Errors

An error is an HTTP status plus one JSON shape: a stable code to branch on and a message for people.

{
    "error": {
        "code": "not_found",
        "message": "No client with that id exists on this account."
    }
}
StatusCodeWhen
400invalid_requestA parameter is malformed: a limit out of range, a bad date, a missing required field.
401invalid_keyNo X-API-KEY header, or the key is unknown.
403resource_not_allowedThe key is a secondary key that was not given this resource.
403plan_not_allowedThe account's plan does not include the API.
403account_unverifiedThe account's e-mail address has not been verified yet.
403account_lockedThe subscription has lapsed. Log in to the app to renew it.
404unknown_resourceThe path is not a v1 resource.
404not_foundNo record with that id exists on this account.
405method_not_allowedThe verb is not supported here; the Allow header lists the ones that are.
413payload_too_largeThe request body is over 256 KB.
409conflictThe change clashes with existing data: a duplicate, or a record that cannot be deleted.
410goneA URL of the retired API. Move to /api/v1/.
429rate_limitedThe hourly limit for this URL and key was reached.
500server_errorSomething failed on our side. Retry, then contact support.
503maintenanceThe service is down for maintenance. Retry shortly.

Rate limits

During the trial each key may call each URL and verb 100 times per hour; on the Enterprise plan, 1,000 times. The count starts with the first call and resets an hour later. A request over the limit answers 429 rate_limited; wait for the window to pass. Read lists in pages of up to 1,000 rather than one record at a time.

Moving a large data set, or another case the standard limit does not fit? Contact support before you start: a higher limit can be set on your key for the time you need it.

Versioning

Every path carries the version, /api/v1/. Within v1 we add fields and endpoints and never remove or rename them; a change that would break your integration ships as a new version with its own path. GET /api/v1 lists the resources of the version you are calling.

The API that lived at /api/{method} before v1 has been retired. Its URLs answer 410 gone with a link here. Updates to the API are announced in the changelog.

Resources

One page per resource: the record's fields and types, every live endpoint with its parameters, and example requests and replies.

Agents

Third parties who pay for or oversee clients (a school district, a parent company): contact details, status, portal permissions and the login record.

Clients

The people your business serves: contact details, status, settings and the login record.

Discounts

Discount codes clients can apply when they pay, with their limits and the services they cover.

Locations

The places sessions happen, with their contact details and the practitioners who work there.

Packages

Session packages the account sells in package mode: a number of sessions for one price. Active and secret packages can be paid for; inactive ones are listed but cannot be; deleted ones are not returned.

Payments

Money received from clients (the revenues ledger), credits included.

Practitioners

The people who deliver your sessions: contact details, status, profile, permissions and the login record.

Services

What you sell: each service with its price, type, booking rules and, for tiered services, its group.

Sessions

Scheduled appointments, lessons and classes. Dates and times are in the account time zone (the timezone field).

Skills

The skill list practitioners are tagged with.

Staff

Your office users: contact details, status, profile, module permissions and the login record.

Timezones

The time zone names accepted in timezone fields, with their UTC offsets.

Users

Login records of everyone on the account (clients, practitioners, staff, agents and the owner), a user's weekly availability, and the custom fields the account defines.