Credential management
Access to our APIs requires a valid credential and unique application secret. Valid credentials are:- An access token
- A ticket
Tenant availability
Online tenants can be in one of several states at any given time and therefore, it is recommended you always check the state of the tenant before sending any requests to the API. There are two options to check a tenant’s current state or be notified of a tenant’s state change, both described in the Tenant status section.API Usage
Applications must be resilient! Every integration must anticipate downtime and incorporate strategies that facilitate redundancy when failures occur or services are unavailable. Your integrations must be able to recover from occasions when errors occur in the middle of important transactions. You must protect customers from losing data if and when the tenant should become unavailable, or posted data contains missing information. Expect problems when interacting with web services and handle unexpected responses at every junction.Mixing APIs
We recommend that each application either use REST or SOAP. Don’t mix multiple APIs in the same application. Read more about which API is right for you in the What API to use section.Caching
Cache all infrequently updated data. The following list contains information that should be asked for very infrequently:- All Lists (business, category, sale type, project type, web panels, and so on)
- All preferences
- Address formats
- Archive and MDO provider names
- Associates
- Countries
- Language information
- User-defined fields
- Data and functional rights
- Module licenses
- User groups
Another big problem integrations make is not taking advantage of caching for authentication tokens. See the credentials management section above.
Think about the APIs you are using and ask yourself “How often does this data change? Is it something I should cache? “Can I subscribe to a webhook and be notified when something changes?” How often does your company change? Then why call GetMyContact 50,000 times a day? Don’t do it!
Entity creation
The entity lifecycle encapsulates the creation, modification, and deletion of all business objects. Each entity contains dependencies derived from preferences, and therefore it is important API consumers create entities using APIs that now about and leverage the preference system. UsingDefault will calculate some of the needed values for you, similar to clicking New inside the SuperOffice client.
For the REST APIs, that means sending a GET request to the appropriate entity to create a default endpoint. The following example demonstrates what you should do.
- RESTful REST API
- AGENT REST API
Proper creation invocation:The following example demonstrates how you should use the
default endpoint. This ensures the returned entity contains all preference-derived data and default data structures.Handle duplicates
When creating new entities, always check whether the record already exists to avoid creating duplicates. This applies especially to contacts and persons. Before creating a new record, search for potential matches and present them to the user so they can choose an existing record or explicitly create a new one. This approach helps maintain data quality and reduces duplicate data in the database. For contacts, you can use the name and department duplicate check provided by the REST API to identify possible existing records before creation.Provisioning
Adding lists, list items, and web panels are just some of the common provisioning tasks when your application elements are provisioned in a tenant. Here are a few things to remember when adding elements into SuperOffice:- Set the visibility of new web panels. Set the appropriate user group and heading options.
- Use the description fields so administrators can easily distinguish which items belong to which application.
- Check out the full list of guidelines on the certification list.
Security
The integrity of SuperOffice must be paramount at all times. While we could list the most obvious things here, like deny network traffic over un-secure connections and establish secure coding practices appropriate to the programming language and development environment being used, we recommend you read our security requirements to learn more.Searching
Web requests are stateless, and therefore every request must stand on its own feet and should not be dependent on the in-memory state left behind by an earlier request. Therefore, whenever you request a page from an archive provider, NetServer has to start from the bottom. An additional constraint comes from the Sentry system, whose rules are too complex to be expressed in something the database can filter for us. We, therefore, have to fetch, evaluate, possibly discard, and go on fetching rows until we arrive at the start of the page you requested. The end result is that the repeated paging is required to fetch data scales like O(N^2). “It’s a feature” - you can call for any page at any time. But like much in the cloud, it leads to implementations that can scale out wonderfully, but still perform badly in some situations. A few things can improve the situation. But the first and most important question is this: Why do you have to repeatedly read so much? When working with a local database, reading a few hundred thousand rows is trivial and a completely valid way to structure your logic. A cloud service with lots of business logic is not the same as a nearby database table. It will never have the same performance, not even close. You must think differently about it and reflect that in your design. When working with a cloud service that’s logically and physically far away, and that by its nature has a different usage pattern, it’s no longer a good solution.Adapting to the cloud doesn’t mean switching from an IDataReader to an ArchiveProvider and keeping everything else the same. While the latter mimics the former, they are fundamentally different in their performance behavior.
Count
Don’t ask for counts. Fetching an accurate count means we have to process every row and the database has to process a SELECT COUNT query. Don’t do it unless absolutely necessary. Instead, use the count aggregation. Looking at the following images, notice how using count(id) causes tremendous load on the server and performs badly.
Instead, consider using the sequence table to get an estimate of how many records a particular table has, and use that value to iterate over all desired records.
The Sequence table has the next primary key id for all tables. Asking for next_id will give the next primary key for any given table. The following example queries the sequence table to obtain the next primary key for the contact table:
SimpleContact, when querying the api/v1/contact endpoint.
Adjust the query to pick up contact_id, OrgNr, and order it by the primary key field. That way you will be able to ask for a pagesize of 1000, the ordering on the table’s primary key is for free and NetServer will not have to perform a lot of expensive data fetching.
Use filters
Archive searches accept a wide variety of search operators. Difference data types can have different operators. Each OData search page contains a table of data types and their associated operators.Optimization
Here are some thoughts for constructing optimal queries:- Design efficient queries. Think about how the queries are translated and executed on the database server.
- Optimize and fine tune your queries. Try a variation of query techniques for a given scenario and choose the one, not that is easiest to implement for the developer, but with the best performance for online services.
- Perform efficient transactions. Target as few fields as possible, use indexed fields, and avoid large table joins. Pre-fetch lists to avoid performing lookups for each record with list IDs.
- Identify and eliminate sub-optimal queries. Instead of creating queries that contain lots of duplicate criterion field restrictions, i.e. contact_id=1 OR contact_id=2 OR contactID=3, use a more appropriate clause that will result in better performance - such as Contact_id IN (1,2,3).
- Test and monitor your data access performance. Do not wait for customer complaints. Have a data performance monitoring strategy, set conservative tolerance thresholds, and take action to refactor problems.
- Always use an $orderby={primarykey}
- Strongly suggest use a filter**=\{criteria\} (especially when using **\top)
- If using $top, use $skip for further optimization. (do NOT ask for all records every request)
Polling
While there may be scenarios where polling thetraveltransactionlog (TTL) table is necessary, it is rarely a good idea and should be considered a last resort.
There are cases where polling the TTL tables are useless. For example, MergeMoveLog records are not persisted in the traveltransactionlog. Neither are SoftDeletes - where the API just sets the deletedDate timestamp on the entity. After 14 days, when they are HardDeleted, this operation is also not written to the traveltransactionlog.
Here is an example search query to fetch which companies have been merged into another company, and actually deleted. The source record is the contact_id (company identity).
Webhooks
Webhooks are notifications sent to your application whenever events happen in SuperOffice - regardless of the SuperOffice product used. They provide you an opportunity to react to many different types of changes, such as new companies created, sales marked as sold, and more. The webhook workflow begins with applications subscribing to interesting events. The way an application does this is by adding one or more webhook definitions in SuperOffice. When a webhook payload is sent, which is a JSON formatted string, it includes information that describes what has changed. However, our security policy is such that the only CRM data sent out is the type of entity that raised the event and the primary ID of said entity. Webhook receivers must authenticate to fetch data about the entity via an API to ensure that they are allowed to read the data.Bulk Operations
Bulk insert, update and delete operations are supported in all SuperOffice APIs. These capabilities exist as:- Bulk-updates
- Mass Operations
The Mass Operations API requires a system user to function.
Bulk-Updates and Mass Operations in the Bulk Operations API documentation.
Logging
Both you and SuperOffice are required to log network communications. Your application must keep logs for a minimum of 3 months. You may be required to provide your log files for security analysis at any time.User interaction and design
Be consistent
- Either use Microsoft Windows standard looks, or copy the SuperOffice CRM looks, but don’t mix the two.
- Avoid having different modes on the same display.
Be action-oriented
- Use buttons to indicate actions.
- In dialogs, place buttons along the bottom ordered like this: Task - OK - Cancel.
-
Deactivate buttons that have no effect.
- Example: the Save button cannot be clicked until the user has changed something.
- Provide explanatory tooltips for deactivated fields and buttons.
-
Prefer selecting from a drop-down list to typing in a text field.
- Provide history or autocomplete if possible.
Use progressive disclosure
- Use a tooltip to show additional information on a list item.
- Hide unnecessary details behind a MORE button.
- Hide actions that are used infrequently behind a TASK menu button.
- Avoid nesting tabs - multiple tab layers are confusing.
Stay informed and share information
- Sign up for email notifications in the forums to learn about changes that might affect your application.
-
Provide feedback to the user if an operation takes time to complete.
- Example: In SuperOffice CRM Online, a cogwheel indicates that a background task is running
- Offer easy access to a knowledge base or to support pages from your application.
- Provide SuperOffice with URLs to your application documentation. Links to the documentation will appear in the App Store.