Authentication:
-
To Stay Logged In: Use an access token. The preferred method is a Bearer Token, where the value to look for is access_token.
Base URLs:
-
New Part: /Microbizz/Api/php/microbizz.php/CONTRACT_NUMBER/
-
Old Part: /api/rest/v1/microbizz.php/CONTRACT_NUMBER/
API Endpoints:
-
Get Access Token:
-
Endpoint: /getaccesstoken?username=ABCDEF@microbizz.com&password=XXXXXXXX
-
Method: GET
-
Description: Retrieves an access token for authentication. The access token should be used in subsequent calls to the REST API, by specifying it in a HTTP header field, like this: Authorization: Bearer MYACCESSTOKEN, or by specifying it in a GET parameter named access_token.
-
-
Retrieve Object:
-
Endpoint: /OBJECT/OBJECTID
-
Method: GET
-
Description: Fetches details of an object by its ID.
-
-
Find Objects with Query:
-
Endpoint: /OBJECT?query={"type": "GreaterEqual", "fieldname": "", "value": "2024-05-18 09:13:50"}
-
Method: GET (FIND)
-
Description: Searches for objects based on a query.
-
-
Create Object:
-
Endpoint: /OBJECT
-
Method: POST (CREATE)
-
Description: Creates a new object with JSON data in the request body.
-
-
Update Object:
-
Endpoint: /OBJECT/OBJECTID
-
Method: POST (EDIT)
-
Description: Updates an existing object with JSON data in the request body.
-
-
Perform Action on Object:
-
Endpoint: /OBJECT/OBJECTID/ACTION
-
Method: POST (ACTION)
-
Example: /todo/4/close
-
Description: Executes a specific action on an object.
-
-
Delete Object:
-
Endpoint: /OBJECT/OBJECTID
-
Method: DELETE
-
Description: Deletes an object by its ID.
-
-
Describe an Object Type:
-
Endpoint: /OBJECT/schema
-
Method: GET
-
Description: Answers the fields the object type has, with the type, whether each is required, read-only, searchable and sortable, and how it is written. The optional fields parameter limits it to the named fields, and naming a field that doesn't exist answers 400. It only names the fields, so it needs no access token and no permission, and it is read-only: any other method answers 405.
-
-
Read Your Permissions:
-
Endpoint: /OBJECT/permissions and /OBJECT/OBJECTID/permissions
-
Method: GET
-
Description: Answers what the caller may do with the object type, or with that one object. See below.
-
-
Contract-Specific Operations:
-
Endpoint: /CONTRACTNO/OBJECT/OBJECTID
-
Description: Used for operations that require a contract number.
-
Key Points:
-
Contract Number: Always include the contract number in the URL for both new and old API endpoints.
-
Authentication: Use the access_token in the Authorization header with the Bearer scheme for all requests after authentication.
-
Method Naming: The EDIT method should ideally be named UPDATE for clarity, but it currently uses the POST method for updates.
This structure provides a clear and concise overview of how to interact with the Microbizz API, ensuring users understand the importance of the contract number and the correct use of access tokens for authentication.
Object permissions
Every object on the new part reports what the caller is allowed to do with it, so a client can hide what it cannot use instead of discovering it through a 403.
|
Endpoint |
Answers |
|---|---|
|
|
What the caller may do with objects of this type. |
|
|
The same, narrowed by what that one object allows. A team that is referred to elsewhere reports |
Any authenticated user may ask, as the answer only describes their own permissions. Only GET is supported; anything else answers 405, and an object type that doesn't exist answers 404. Asking about a single object requires being allowed to read the type, so that the answer cannot be used to find out which IDs exist.
The four flags create, read, update and delete are always present, also when they are false, so nothing has to be read into their absence. special holds the permissions that are specific to the object, and is an object also when it is empty. The names in it differ per object — a role reports assign_users, a company subscriptions and edit_subscriptions — and more may be added over time, so read the ones you know and ignore the rest.
{"object":"role","id":7,"create":true,"read":true,"update":true,"delete":false,"special":{"assign_users":true}}
What is reported is what the API enforces. Every object type is guarded before any handler runs, so a request the permissions deny is refused without the body being looked at, and nothing is read or written. The only paths outside that are /OBJECT/schema, which just names the fields and needs no token, and /OBJECT/permissions itself.
|
Status |
When |
|---|---|
|
|
The access token is missing or invalid. This is answered before any permission is looked at, so a |
|
|
The caller may not perform the operation on this object type, or not on this object. |
|
|
The name is not an object type, or the object doesn't exist. |
|
|
The method is not one of |
Which permission each operation needs is decided per object, and the permissions are the same ones that gate the corresponding pages in the web system: whatever a user cannot do there, they cannot do through the API either. The codes per object are listed on Microbizz\Api, and /permissions is the answer for the caller at hand.
A permission that depends on the values being written cannot be answered before the request is read, so it is reported as a 400 with an explanation rather than a 403. Writing a work plan registration for another user is the example below.
Object commands
Besides the endpoints above an object may answer commands of its own on /OBJECT/OBJECTID/COMMAND, like the binary commands on a file and the membership commands on a role or a team. A command the object doesn't support answers 400.
A command is behind the permission of the method it uses, so a GET command needs read and a POST command needs update on the object. A command may require more than that, and the ones below say so where they do.
The Swagger export under Data > REST API lists the commands of every object together with the method they take.
Files and documents
The file object is available on both parts of the API and represents a document. Its content is not a field on the object, so it is transferred either as base64 inside the object or through the binary commands below.
Reading and writing the content
|
Command |
Purpose |
|---|---|
|
|
Answers the document itself, with |
|
|
Replaces the content, and answers the resulting |
Neither command base64 encodes the content, so they are the cheap way to move anything but a small file.
setbinary takes the content in one of two ways:
-
As the raw file in the request body. The
Content-Typeheader states the mimetype and?filename=names the file; the existing filename is kept when it is omitted. -
As a file object in a JSON body, as described below.
A JSON body is only read as a file object when it holds at least one of the properties action, filename, mimetype or binary, so a JSON document can still be posted as raw content.
The file object
A field holding a file or an image is written by passing this object, which is also what setbinary accepts as a JSON body:
|
Property |
Meaning |
|---|---|
|
|
Either |
|
|
Name of the file. Required unless |
|
|
Mimetype of the content. An explicit mimetype wins over the one derived from an uploaded file. |
|
|
The content, base64 encoded. |
|
|
Name of a file already uploaded to the temp folder, as an alternative to |
When reading, a file field holds the internal ID of the file. Set include_binary_data=1 to have the content included as base64 as well; on the file object itself this adds a binary property. Responses can become very large, so prefer getbinary for anything but small files.
Roles and teams
The user module exposes roles and teams on the new part as the role and the team object. Both are read, created, updated and deleted like any other object, and both answer commands for the users they hold.
The objects
|
Object |
Key |
Fields |
|---|---|---|
|
|
|
|
|
|
|
|
GET /role/schema and GET /team/schema answer the authoritative field list, and need no access token. Creating answers 201 with the object that was made, while a create that leaves out a required field answers 400 and stores nothing.
Deleting a role takes it off the users holding it and deletes the permissions granted to it. A team cannot be deleted while something still refers to it, which GET /team/TEAMID/permissions reports as delete being false.
The users of a role or a team
|
Command |
Purpose |
|---|---|
|
|
Answers |
|
|
Grants the role to the users in the body. Answers |
|
|
Revokes the role from the users in the body. Answers the same, with |
|
|
Answers |
|
|
Puts the users in the body in the team. Answers |
|
|
Takes them out of the team. Answers the same, with |
The body names the users either as a single user_id or as a user_ids list, and may hold nothing else:
{"user_ids":[5,12]}
The commands are idempotent. A user who already holds the role, or already is in the team, is not reported as changed, and the call still answers 200. Every user in the body is checked before anything is changed, so a request naming one bad user changes nothing at all.
|
Status |
When |
|---|---|
|
|
The body is not a JSON object holding |
|
|
The caller may not use the command, or may not access one of the users named. |
|
|
One of the users named doesn't exist. |
Permissions
Roles and teams are administered in the user module, so they are guarded by the same permissions as the configuration pages for them:
|
Operation |
|
|
|---|---|---|
|
create |
|
|
|
read |
|
|
|
update |
|
|
|
delete |
|
|
|
the membership commands |
|
|
All of them are permissions in the user module. The membership commands change the users rather than the role or the team, so they need permission to edit users on top of the permission that gets the request through. GET /role/permissions reports that as assign_users in special, and GET /team/permissions as add_users.
The roles a user holds in a team
Team roles are not on the team; they are on the user, in its teams field, and are written by posting that field to the user, eg. POST /user/42:
{"teams":[{"team":3,"team_roles":[7,9]}]}
Each element is an object of team, the ID of the team, and team_roles, the IDs of the roles the user holds in that team. team_roles may be left out or empty. The field is written as a whole, so a post has to carry every team the user is to be in.
A value that doesn't match that shape is refused with 400 and nothing is stored, whether it is a flat list of team IDs, an element carrying an unknown property, a team that doesn't exist, or a team_roles that isn't a list.
The roles a user holds outside of any team are the separate roles field, a list of role IDs, which is also what assignuser writes. adduser on a user who already is in the team changes nothing, so it never clears the team roles they hold, while removeuser drops them along with the membership.
Work plan
The workplan module exposes the work plan on the new part as two objects: workplan, which is one registration per user per date, and workplantype, the registration types the contract has defined. Both are kept in step with the work plan in the web system, so a change made on either side shows up on the other.
workplan
|
Field |
Meaning |
|---|---|
|
|
Key. |
|
|
The user the registration is for. Required. |
|
|
The date it covers, as |
|
|
What the day is. Required. |
|
|
Whether the registration is locked against further changes. |
There is one registration per user per date. When a registration is changed from the web system the row is replaced rather than updated, so its ID changes; a client that has stored IDs should look a registration up by user_ref and date rather than assume the ID it saw is still there. A registration is also hard deleted, so it disappears from the list rather than being marked as deleted.
A work plan is only filled in from the day it is written or burned, so a date with no registration simply has no object. Until the work plan of an existing solution has been transferred to the new part, GET /workplan answers an empty list rather than an error.
workplantype
The eight built-in types, 0 to 7, are not objects: they are configured per contract and exist only as the numbers above. workplantype holds the custom types, and their IDs start above the built-in ones, so a registration value identifies a type across both kinds. A type whose ID would collide with a built-in one is refused.
|
Field |
Meaning |
|---|---|
|
|
Key, which is also the value a registration holds. |
|
|
Short code shown in the work plan. |
|
|
The name of the type. Required. |
|
|
Which built-in type it behaves as, using the same numbers as |
|
|
Colour used in the work plan, as a hex value. |
|
|
Whether a time registration is made when the type is used. |
|
|
What the time is registered on when it is sent to registration. |
|
|
Whether |
|
|
The duration to register, in whole minutes. |
|
|
The internal registration type, tracking account, task and work area the time is registered on, each as an ID or |
Permissions
Both objects are guarded by the workplan module:
|
Operation |
|
|
|---|---|---|
|
create, update, delete |
|
|
|
read |
|
|
Everybody with edit may manage their own work plan; anybody else's takes edit_others on top, which GET /workplan/permissions reports in special. Without it, reading, changing or deleting another user's registration answers 403, while creating a registration for another user answers 400 with an explanation, as the user it is for is only known once the body has been read. This is stricter than the work plan page in the web system, which lets anybody with edit change any user's plan.
Reading a work plan type takes no more than access to the module, as every registration names one and would otherwise be a number with no meaning. Creating and changing types is the work plan configuration, and takes types.
Writable fields on the old part
The old part accepts more field types than it used to:
-
A reference to another object can be set by passing its ID. The object must exist, otherwise the call is rejected. Where the type does not identify one single class — a plain internal ID, or a type shared by several classes — the ID is stored without being verified.
-
Country fields are free text, as both codes and names occur in the database. A two letter code is upper-cased.
-
A module code must be a modcode the system knows.
-
HTML fields are reduced to the tags the editor allows, and broken HTML is repaired.
-
Fields holding whole numbers, eg. a duration in minutes, are stored as integers rather than floats.
-
An empty string is accepted for an email field. Filename fields cannot be set.
-
Any other type is rejected with an explanation rather than silently ignored.
When creating an object, the required fields are checked against what the request actually sent.
Query commands
Query commands should contain three fields: type, fieldname and value
|
Greater |
Return everything where fieldname is greater than value. |
|
GreaterEqual |
Return everything where fieldname is greater or equal than value. |
|
Lesser |
Return everything where fieldname is lesser than value. |
|
LesserEqual |
Return everything where fieldname is lesser or equal than value. |
|
Like |
Return everything where value is contained in fieldname. |
|
Match |
Return everything where fieldname equals value. |
|
OneOf |
Return everything where fieldname is one of value (value should be an array). |
Logical commands
Logical commands contains a type and one or more conditions which are further query or logical commands.
|
AND |
condition1, condition2 |
Return everything which satisfies both condition1 and condition2. |
|
OR |
condition1, condition2 |
Return everything which satisfies either condition1 or condition2. |
|
NOT |
condition |
Return everything which doesn't satisfy condition. |
Examples
Find all data where age is equal or greater than 18
|
|
Find all data where age is less than 40 and gender is male
|
|
Find all data where firstname contains the letter a
|
|
Find all data changed since a specific time stamp
|
|