---
title: Setup
description: >-
  In order to set up and use the Data Export API from Survicate, there are some
  prerequisites that must be fulfilled.
source_url:
  html: 'https://developers.survicate.com/data-export/setup/'
  md: 'https://developers.survicate.com/data-export/setup.md'
---
# Setting up the Data Export API

In order to set up and use the Data Export API from Survicate, there are some prerequisites that must be fulfilled.

## Prerequisites

1. **Survicate Account:** First and foremost, you must have an account with Survicate. If you don't already have one, you can create your account at panel.survicate.com. Alternatively, you can join your company's account if you've received an invitation from a colleague.

2. **Proper Subscription:** Secondly, to use the Data Export API, your Survicate account must be subscribed to a plan that includes API access. Please note that without a valid subscription, any API requests will result in an error response. Please review Survicate's plans and make sure you're subscribed to the one that best suits your needs and includes API access.

## Endpoints

To connect to the Data Export API endpoints, use the base URL:
```
https://data-api.survicate.com/v2/
```

## Authentication
Once you've fulfilled the prerequisites, you're ready to start using the Data Export API.

To authenticate yourself and begin your data exports, you'll need your API key. You can find it in the Survicate panel under **Settings → Organization → Access Keys**. Only organization owners and workspace admins can open that page.

Once you have your API key, you'll need to provide it for authentication purposes. The API key should be included in the `Authorization` header of your API requests. The format for this should be `Basic {{apiKey}}`. Remember to replace `{{apiKey}}` with your actual API key when making requests.

```shell
curl  -H 'Authorization: Basic {{apiKey}}'
```

That's it! With your account set up, the right subscription, and your API key, you're ready to start using Survicate's Data Export API. Enjoy your journey in capturing and analyzing user feedback for better insights and business decisions!

## Pagination

All list endpoints in the Data Export API are paginated. There are no page numbers - instead of asking for `page=2`, you follow the link the API gives you in each response.

### Result order and the date range

Results are ordered from the latest to the oldest record. The `start` and `end` parameters mark the two ends of that range, in that order:

- `start` is the **newer** bound and the point the page starts from. Records collected at or before it are included.
- `end` is the **older** bound. Records collected at or after it are included.

Both bounds are **inclusive**, and because of the ordering `start` must be later than `end`. Timestamps use ISO 8601 with microseconds, for example `2024-08-31T23:59:59.000000Z`.

So to export everything collected between August 26 and August 31, 2024, the two timestamps are swapped compared to what you might expect:

```shell
curl -H 'Authorization: Basic {{apiKey}}' \
  'https://data-api.survicate.com/v2/surveys/{survey_id}/responses?start=2024-08-31T23:59:59.000000Z&end=2024-08-26T00:00:00.000000Z'
```

### Page size

`items_per_page` accepts a value between 1 and 100. It is optional - if you omit it, the API applies its own default page size.

### Following `next_url`

Every list response contains a `pagination_data` object:

```json
{
  "pagination_data": {
    "has_more": true,
    "next_url": "/surveys/69f3dcf0d3220de7/responses?start=2024-08-29T09:12:44.128000Z&end=2024-08-26T00:00:00.000000Z"
  },
  "data": [...]
}
```

- `has_more` tells you whether another page exists.
- `next_url` is **always a path relative to the base URL** `https://data-api.survicate.com/v2`, never an absolute URL. Prepend the base URL and request the path as-is, without rebuilding the query string yourself.

Under the hood `next_url` moves the `start` timestamp back to where the previous page ended, keeping your original `end` and any filters intact. Because Survicate builds that link for you, you don't need to work out the next boundary or worry about skipping records.

### A complete walkthrough

**Request 1** - the first page of responses collected between August 26 and August 31, 2024, 100 at a time:

```shell
curl -H 'Authorization: Basic {{apiKey}}' \
  'https://data-api.survicate.com/v2/surveys/69f3dcf0d3220de7/responses?start=2024-08-31T23:59:59.000000Z&end=2024-08-26T00:00:00.000000Z&items_per_page=100'
```

```json
{
  "pagination_data": {
    "has_more": true,
    "next_url": "/surveys/69f3dcf0d3220de7/responses?start=2024-08-29T09:12:44.128000Z&end=2024-08-26T00:00:00.000000Z&items_per_page=100"
  },
  "data": [...]
}
```

**Request 2** - take `next_url`, prepend the base URL, and call it:

```shell
curl -H 'Authorization: Basic {{apiKey}}' \
  'https://data-api.survicate.com/v2/surveys/69f3dcf0d3220de7/responses?start=2024-08-29T09:12:44.128000Z&end=2024-08-26T00:00:00.000000Z&items_per_page=100'
```

```json
{
  "pagination_data": {
    "has_more": true,
    "next_url": "/surveys/69f3dcf0d3220de7/responses?start=2024-08-27T16:40:02.905000Z&end=2024-08-26T00:00:00.000000Z&items_per_page=100"
  },
  "data": [...]
}
```

**Request 3** - keep going until `has_more` is `false`. That response is the last page; stop there even if a `next_url` is present:

```json
{
  "pagination_data": {
    "has_more": false
  },
  "data": [...]
}
```

In code, the loop is simply: call the endpoint, process `data`, and while `has_more` is `true`, request `https://data-api.survicate.com/v2` + `next_url` again.

> **Note:**
> Keep the 5 concurrent request limit in mind - pages must be fetched one after another, since you only learn the next URL from the previous response.

## Attributes

Responses and respondents can carry **attributes**: name/value pairs such as `order_id`, `store` or `state`.

Every attribute is one you passed to Survicate yourself - through the [JavaScript SDK](/javascript/methods), a mobile SDK, an integration, or the survey link. The names you get back are the names you set, and the values are always returned as strings. Survicate does not add reserved or native attributes of its own, so there is no reserved vs. custom distinction to handle: if a field like `survey_type` shows up in an attributes array, it is there because it was sent to Survicate.

A response carries two attribute arrays: `respondent.attributes` holds the attributes of the person, and the top-level `attributes` array holds attributes recorded with that specific response. On the [responses list endpoint](/data-export/response) both are returned only for the names you list in the `attributes[]` query parameter — when it is omitted, both arrays are empty. The single-response endpoint always returns the response-level `attributes` in full and applies the parameter only to `respondent.attributes`.

### Requesting attributes

Repeat `attributes[]` once per attribute name — the bracket notation is required. When testing with curl, add `-g` so curl passes the brackets through instead of treating them as its own globbing syntax (some curl versions fail with `bad range in URL` otherwise):

```shell
curl -g -H 'Authorization: Basic {{apiKey}}' \
  'https://data-api.survicate.com/v2/surveys/{survey_id}/responses?attributes[]=order_id&attributes[]=store'
```

Each response in `data` then carries the matching values inline, with no extra requests. A requested name is returned wherever it exists — an attribute recorded with the response lands in the top-level `attributes`, an attribute of the person under `respondent.attributes` (the other response fields are omitted from this example):

```json
{
  "uuid": "15263384-6a46-47d3-bf4a-9aa3d05a5277",
  "attributes": [
    { "name": "store", "value": "Berlin" }
  ],
  "respondent": {
    "uuid": "4a607bc1-a2ca-42a7-be37-b888a741ee31",
    "attributes": [
      { "name": "order_id", "value": "A-1024" }
    ]
  }
}
```

A requested attribute the response or respondent doesn't have is simply absent from the arrays. The parameter combines with all other parameters (`start`, `end`, `items_per_page`, `filters`), and `next_url` keeps it across pages.

Fields that Survicate always returns - `uuid`, `collected_at`, `url`, `device_type`, `operating_system`, `platform`, `language`, `answers` and `respondent` - are top-level properties of a response, not attributes. See [Response](/data-export/response) for the full schema.

## Rate limiting
Survicate implements a set of rate limiting measures designed to protect our infrastructure from overwhelming traffic spikes. Adhering to these limits ensures that our services remain stable and available for all users. The rate limits are as follows:

- **Concurrent Request Limit:** You can make up to 5 concurrent (simultaneous) API requests. To avoid breaching this limit, design your system to wait for a response from your current request before initiating another. This mechanism helps ensure that your operations do not overload the system with multiple simultaneous demands.
- **Workspace Request Limit:** There's a cap of 1000 requests per minute for each workspace. This limit safeguards the system from an excessive number of requests within a short timeframe, enabling the fair and efficient use of our resources across all users.

In the event that you exceed any of these limits, our system will respond with a `429 Too Many Requests` status code. This code serves as a signal that your operation has been temporarily blocked due to excessive requests. It is, therefore, important to manage your requests to stay within these bounds, ensuring smooth operations and uninterrupted API access.

If you have any questions or require assistance, our support team is ready to help. Please use the live chat feature located in the bottom right corner of your screen. We're here to ensure your experience is smooth and efficient.
