> ## Documentation Index
> Fetch the complete documentation index at: https://docs.crosoftware.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Getting Started

> Start integrating with the CRO Developer API

The first thing to do is acquire access credentials from CRO software. Please review the [Authentication Guide](/guides/authentication) for more information.

## Base URL

```
https://api.crosoftware.com/v0
```

All endpoint paths in this documentation are relative to this base URL. If you have integration code or examples referencing an older `crosoftware.net`-based URL, update it to the value above: the production API and its base domain migrated to `api.crosoftware.com`.

## 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](/guides/authentication) for more on how to authenticate your applications.

## Errors

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 response:

```json theme={null}
{
  "field": "CreateCustomerModel.user_id",
  "detail": "Unknown field.",
  "explanation": "The resource could not be accessed."
}
```

In this example, you could refer to the CreateCustomerModel schema in the [API Reference](/api-reference) 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.

## Roles

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

```
Public
Admin
Driver
Dispatcher
CrmUser
ClientCustomer
ThirdPartyDispatcher
ThirdPartyDriver
```

`ThirdPartyDispatcher` and `ThirdPartyDriver` are a separate, parallel hierarchy from the first-party roles above, not a nested extension of them. See the [FAQ](/guides/faq#whats-the-difference-between-first-party-and-third-party-roles) for details.

## Sample Script: Export Customers

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

If you're not sure what these values should be, contact us at [crodev@rapidworks.com](mailto:crodev@rapidworks.com).

<CodeGroup dropdown>
  ```bash cURL theme={null}
  curl -X GET 'https://api.crosoftware.com/v0/customers' \
    -H 'Authorization: bearer <your-token-here>' \
    -H 'x-tenant-id: <your-tenant-id-here>' \
    -H 'content-type: application/json'
  ```

  ```python Python theme={null}
  import requests

  url = 'https://api.crosoftware.com/v0/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)
  print(response.text)
  ```

  ```javascript JavaScript theme={null}
  const url = 'https://api.crosoftware.com/v0/customers';
  const headers = {
    'Authorization': 'bearer <your-token-here>',
    'x-tenant-id': '<your-tenant-id-here>',
    'content-type': 'application/json'
  };

  const response = await fetch(url, { headers });
  const data = await response.json();
  console.log(data);
  ```
</CodeGroup>

This uses the [requests library](https://requests.readthedocs.io/) for Python; the JavaScript sample uses the built-in `fetch` (Node.js 18+ or a browser).

### Response

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.

```json theme={null}
{
  "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": "test@contacts.com",
          "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
    },
    ...
  ]
}
```

### Paging

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

```json theme={null}
{
  "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:

<CodeGroup dropdown>
  ```bash cURL theme={null}
  url='https://api.crosoftware.com/v0/customers'
  page=1

  while :; do
    response=$(curl -s "$url?page_index=$page" \
      -H 'Authorization: bearer <your-token-here>' \
      -H 'x-tenant-id: <your-tenant-id-here>' \
      -H 'content-type: application/json')

    echo "$response" | jq -c '.results[]'

    total_pages=$(echo "$response" | jq '.total_pages')
    page=$(( $(echo "$response" | jq '.current_page') + 1 ))
    [ "$page" -gt "$total_pages" ] && break
  done
  ```

  ```python Python theme={null}
  import requests, json


  def process_customers(cb, **kw):
      url = 'https://api.crosoftware.com/v0/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(url, headers=headers, params=params)
          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:
              break


  process_customers(print)
  ```

  ```javascript JavaScript theme={null}
  const url = 'https://api.crosoftware.com/v0/customers';
  const headers = {
    'Authorization': 'bearer <your-token-here>',
    'x-tenant-id': '<your-tenant-id-here>',
    'content-type': 'application/json'
  };

  async function processCustomers(cb) {
    let nextPage = 1;
    let totalPages;

    do {
      const response = await fetch(`${url}?page_index=${nextPage}`, { headers });
      const results = await response.json();
      results.results.forEach(cb);
      totalPages = results.total_pages;
      nextPage = results.current_page + 1;
    } while (nextPage <= totalPages);
  }

  processCustomers(console.log);
  ```
</CodeGroup>

The cURL sample uses [jq](https://jqlang.org/) to parse the JSON response between requests.
