Skip to main content

Getting Started

The first thing to do is acquire access credentials from CRO software. Please review the Authentication Guide for more information.

Tokens, Scopes, Users, & Passwords

An access token is used to authenticate your software to the CRO Developer API. The user and password are used to authenticate users to your software. Scopes determine what functionality your software will have access to. See the Authentication Guide for more on how to authenticate your applications.


All errors are handled similarly. The HTTP response status line will describe what happened (human readable):

400 CreateCustomerModel.user_id: Unknown field.

...and the body will contain a structured reponse:

"field": "CreateCustomerModel.user_id",
"detail": "Unknown field.",
"explanation": "The resource could not be accessed."

In this example, you could refer to the CreateCustomerModel for more information about the expected fields. Input errors will contain a model name and/or field names that can be referenced in the documentation. The 'detail' field of the error schema will contain the reason the request was rejected.

Request Data Formats

Currently only JSON is supported.

Response Data Formats

Currently only JSON is supported. Some endpoints may return reports in other formats; refer to each endpoint's documentation for details.


The access token(s) you'll be issued grant you access to the API. The scope(s) granted to each token determine which API functions you can access. The CRO user you log in with determines which role(s) are assigned. The roles the user is assigned determine which endpoints are accessible and also what data is returned by each endpoint. Refer to each endpoint's documentation for details on which roles have access and what data will be returned.

Available Roles


Sample Script: Export Customers

In this sample we'll export customers using the CRO Developer API and the requests library. Refer to the code below. Replace 'your-token-here', 'my-api-url-here', and 'your-tenant-id-here' with the values issued by CRO Software.

If you're not sure what these values should be, contact CRO Software.

import requests
url = 'http://<my-api-url-here>/customers'
headers = {
'Authorization': 'bearer <your-token-here>',
'x-tenant-id': "<your-tenant-id-here>",
'content-type': 'application/json'
params = {}
response = requests.get(url, headers=headers, params=params)


Note the response from /customers is a paged result set. All endpoints in the API return lists as paged responses with this format. In the next section we'll iterate the results and print them to the console.

"current_page": 1,
"current_limit": 100,
"total_pages": 6,
"total_count": 504,
"results": [
"addresses": [
"is_active": true,
"is_billing": true,
"is_physical": true,
"is_shipping": true,
"country": "US",
"id": 1,
"latitude": 54,
"line_1": "123 Some St.",
"line_2": null,
"line_3": null,
"line_4": null,
"locality": "Sequim",
"longitude": 128,
"postcode": "98368",
"region": "WA"
"contacts": [
"notify_on_acknowledged_request": false,
"notify_on_completed_request": false,
"notify_on_dispatched_request": false,
"notify_on_failed_request": false,
"notify_on_new_request": false,
"email": "",
"fax": null,
"id": 1,
"name": "Sarah Jane",
"number": null
"created_on": "2020-10-19T04:06:50.733000",
"last_updated_on": "2020-10-19T04:06:50.733000",
"name": "Customer A",
"parent_id": null,
"customer_id": 1,
"is_active": true,
"is_commercial": false,
"location_id": 1,
"note": null,
"reference_number": "1234",
"renewal_date": null,
"sales_rep": "A Sales Guy",
"sales_rep_id": null,
"suspension_id": null


The fields of a paged result set have the same basic schema:

"current_page": 1,
"current_limit": 100,
"total_pages": 6,
"total_count": 504,
"results": ...

To iterate through all customers, you need to write the code to request the pages in a loop:

import requests, json

def process_customers(cb, **kw):
url = 'http://<my-api-url-here>/customers'
headers = {
'Authorization': 'bearer <your-token-here>',
'x-tenant-id': "<your-tenant-id-here>",
'content-type': 'application/json'
next_page = 1
while True:
params = {
'page_index': next_page
response = requests.get(
results = json.loads(response.text)
for item in results['results']:
cb(item, **kw)
total_pages = int(results['total_pages'])
next_page = int(results['current_page']) + 1
if next_page > total_pages: