# API documentation (Beta)

Use the RandomCoffee API to create attributes, upload users and read user participation data.

import { Badge } from '@prosefly/astro-components';
import Callout from '@components/Callout.astro';

<Callout type="note">
  Our API is currently in beta, and we’re continuously working to improve it. If you have any questions, feature requests, or suggestions for improvement, we’d love to hear from you. Your feedback helps us make the API better for everyone!
</Callout>

## Prerequisites

- A **RandomCoffee** workspace on the **Enterprise Plan**

### Base URL

```text
https://api.random-coffee.com/api/v2
```

### Authentication

All endpoints require an API token for authentication. The token should be passed in the `Authorization` header using the `Bearer` schema.

Example:

```text
Authorization: Bearer YOUR_API_TOKEN
```

### 1. Create a Category / Attribute

### <Badge color="success">POST</Badge> `/data/attributes/`

Create a new category or attribute for your company.

**Request Body:**

```json
{
    "title": "Location",
    "description": "User's workplace location",
    "type": "select",
    "values": ["New York", "San Francisco", "Chicago"]
}
```

**Request Body Parameters:**

- `title` (string, required): The name of the category or attribute (e.g., "Location").
- `description` (string, required): A description of the category or attribute (e.g., "User's workplace location").
- `type` (string, optional): The type of the category. Can be `"select"` , `"text"` , `"date"`, `"integer"` ,`"array"` or `"boolean"`. Default is `"select"`.
- `values` (array, optional): A list of predefined values for the category. Only applicable if the `type` is `"select"` or `"array"`.

**Response:**

- HTTP Status Code: `201 OK` on success.
- Returns the created category/attribute details.

```json
{
    "id": 1,
    "title": "Location",
    "description": "User's workplace location",
    "type": "select",
    "values": ["New York", "San Francisco", "Chicago"],
    "created_at": "2025-01-14T00:00:00Z"
}
```

### 2. Get Categories/Attributes

### <Badge color="info">GET</Badge> `/data/attributes/`

Retrieve a list of all categories and attributes associated with your company.

**Response:**

- HTTP Status Code: `200 OK` on success.
- Returns a list of categories/attributes.

```json
[
    {
        "id": 1,
        "title": "Location",
        "description": "User's workplace location",
        "type": "select",
        "values": ["New York", "San Francisco", "Chicago"],
        "created_at": "2025-01-14T00:00:00Z"
    },
    {
        "id": 2,
        "title": "Department",
        "description": "User's department",
        "type": "text",
        "values": [],
        "created_at": "2025-01-14T00:00:00Z"
    }
]
```

### 3. Upload Users

### <Badge color="success">POST</Badge> `/data/uploads/`

Upload a list of users in bulk along with their associated attributes.

**Request Body:**

```json
{
    "users": [
        {
            "first_name": "John",
            "last_name": "Doe",
            "email": "john.doe@example.com",
            "extra_data": {
                "Location": "New York",
                "Department": "Engineering"
            }
        },
        {
            "first_name": "Jane",
            "last_name": "Doe",
            "email": "jane.doe@example.com",
            "extra_data": {
                "Location": "San Francisco",
                "Department": "Marketing"
            }
        }
    ]
}
```

**Request Body Parameters:**

- `users` (array, required): A list of users to upload. Each user must have:
  - `first_name` (string, required)
  - `last_name` (string, required)
  - `email` (string, required)
  - `extra_data` (object, optional): Custom attributes and their values (e.g., `"Location": "New York"`).

**Response:**

- HTTP Status Code: `201 OK` on success.
- Returns the details of the upload.

```json
{
    "id": 123,
    "finished_processing_at": null,
    "results": {"errors": [], "users": {}},
    "created_at": "2025-01-14T00:00:00Z"
}
```

---

### 4. Get Upload Details

### <Badge color="info">GET</Badge> `/data/uploads/{upload_id}/`

Retrieve the details of a specific upload by its ID.

**URL Parameters:**

- `upload_id` (integer, required): The ID of the upload.

**Response:**

- HTTP Status Code: `200 OK` on success.
- Returns the details of the upload, including processing results.

```json
{
    "id": 123,
    "finished_processing_at": null,
    "results": {"errors": [], "users": {}},
    "created_at": "2025-01-14T00:00:00Z"
}
```

### 5. Get User Details

### <Badge color="info">GET</Badge> `/data/users/{email}/`

Retrieves detailed information about a specific user, identified by their email address.

**URL Parameters:**

- `email` (string, required): The user's email address.

**Response:**

- HTTP Status Code: `200 OK` on success.
- Returns a JSON object containing user information and participation metrics.

```json
{
    "email": "thierry.john@company.com",
    "first_name": "Thierry",
    "last_name": "John",
    "is_active": true,
    "randomcoffee_count": 13,
    "last_randomcoffee_date": "2025-06-10T09:30:00Z"
}
```

### 6. Get Users List

This endpoint allows you to retrieve the list of users belonging to your organization.

### <Badge color="info">GET</Badge> `/data/users/`

The `Get Users List` endpoint returns a paginated list of users along with their participation metrics.

You can control the number of users returned per page using the `limit` parameter, and iterate through all pages using the `next` value provided in the response.

You can also apply **filters** to retrieve only users matching specific criteria (e.g., only active users).

**Response:**

- HTTP Status Code: `200 OK` on success.
- Returns a JSON object containing pagination info and user details.

```json
{
    "count": 1,
    "next": null,
    "previous": null,
    "offset_start": 1,
    "offset_end": 1,
    "results": [
        {
            "email": "thierry.john@company.com",
            "first_name": "Thierry",
            "last_name": "John",
            "is_active": true,
            "randomcoffee_count": 13,
            "last_randomcoffee_date": "2025-06-10T09:30:00Z"
        }
    ]
}
```

**Pagination**

Results are **paginated** to improve performance.

Each response includes:

- `results`: the list of users for the current page
- `next`: a URL to the next page of results (or `null` if there are no more results)
- `previous`: a URL to the previous page of results (or `null`)

You can use the `limit` parameter to specify the maximum number of users per page (default: 10).

**Example pagination flow:**

1. Call the endpoint with `?limit=50`
2. Parse the response and collect `results`
3. If the `next` field is not null, call the next URL
4. Continue until `next` is null

**Filtering**

You can apply filters to the users list by passing a `filters` parameter as a JSON string.

The filters follow a structured schema supporting:

- **version** : filtering schema version (currently `"v1"`)
- **operator** : logical operator (`"and"` or `"or"`)
- **filters** : list of conditions with:
  - `type`: the field to filter on (e.g., `is_active`, `email`, `first_name`, `last_name`)
  - `operator`: comparison operator (`eq`, `ne`, `in`, etc.)
  - `value`: value(s) to compare against

### Example filter object

```json
{
  "version": "v1",
  "operator": "or",
  "filters": [
    { "type": "is_active", "operator": "eq", "value": 1 }
  ]
}
```

This retrieves only users who are **active** (`is_active = 1`).

---

### Example: Retrieve All Active Users (Python Language)

```python
import requests
import json

BASE_API_URL = "https://api.random-coffee.com/api/v2"

def get_users(filters=None):
    url = f"{BASE_API_URL}/data/users/?limit=50"
    if filters:
        url += f"&filters={filters}"
    data = []
    while url:
        resp = requests.get(url, headers={
            "Authorization": "Bearer {{KEY}}"
        }).json()
        data.extend(resp["results"])
        url = resp["next"]
    return data

# Define filter for active users
filters = json.dumps({
    "version": "v1",
    "operator": "or",
    "filters": [{"type": "is_active", "operator": "eq", "value": 1}]
})

active_users = get_users(filters=filters)
```

### Example: Retrieve Inactive Users

```python
inactive_filters = json.dumps({
    "version": "v1",
    "operator": "or",
    "filters": [{"type": "is_active", "operator": "eq", "value": 0}]
})

inactive_users = get_users(filters=inactive_filters)
```

### Example: Retrieve Users by Last RandomCoffee Date

```python
by_last_randomcoffee_date_filters = json.dumps({
    'version': 'v1',
    'operator': 'or',
    'filters': [{
        'value': '2025-09-10',
        'operator': 'gte',
        'type': 'last_randomcoffee_date'
    }]
})

users = get_users(filters=by_last_randomcoffee_date_filters)
```

### Error Handling

- `401 Unauthorized`: Missing or invalid authentication token.
- `403 Forbidden`: Invalid token or insufficient permissions.
- `400 Bad Request`: Invalid request data (e.g., missing required fields).
- `404 Not Found`: Resource not found.
- `405 Method Not Allowed`: Invalid HTTP method for the resource.

### Rate Limiting

This API is rate-limited to prevent abuse. Make sure to handle the `429 Too Many Requests` status by retrying after the specified duration.

### Example Tests

Here are some test cases for these routes:

### Test Case 1: Create Category

```python
import requests

BASE_API_URL = "https://api.random-coffee.com/api/v2"

response = requests.post(f'{BASE_API_URL}/data/attributes/', json={
    "title": "Location",
    "description": "User's workplace location",
    "type": "select",
    "values": ["New York", "San Francisco"]
}, headers={"Authorization": "Bearer YOUR_API_TOKEN"})
assert response.status_code == 201
assert response.json()['title'] == "Location"
```

### Test Case 2: Upload Users

```python
import requests

BASE_API_URL = "https://api.random-coffee.com/api/v2"

response = requests.post(f'{BASE_API_URL}/data/uploads/', json={
    "users": [
        {
            "first_name": "John",
            "last_name": "Doe",
            "email": "john.doe@example.com",
            "extra_data": {"Location": "New York"}
        },
        {
            "first_name": "Jane",
            "last_name": "Doe",
            "email": "jane.doe@example.com",
            "extra_data": {"Location": "San Francisco"}
        }
    ]
}, headers={"Authorization": "Bearer YOUR_API_TOKEN"})
assert response.status_code == 201
```

### Test Case 3: Get Upload Details

```python
import requests

BASE_API_URL = "https://api.random-coffee.com/api/v2"

response = requests.get(
    f'{BASE_API_URL}/data/uploads/123/',
    headers={"Authorization": "Bearer YOUR_API_TOKEN"}
)
assert response.status_code == 200
assert response.json()['id'] == 123
```
