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

# Quickstart

> Make your first COR API call in under 5 minutes

This guide walks you through authenticating with the COR API and making your first requests to manage projects, tasks, and time entries.

<Info>
  **Prerequisites**: Before you begin, make sure you have your API credentials ready. See the [Development guide](/development) to learn how to obtain your API Key and Client Secret from the COR dashboard.
</Info>

## Step 1: Get an access token

COR uses OAuth 2.0 for authentication. The **Client Credentials** flow is recommended for server-to-server integrations.

### Encode your credentials

First, create a Base64 encoded string of your API Key and Client Secret:

```bash theme={null}
echo -n "YOUR_API_KEY:YOUR_CLIENT_SECRET" | base64
```

This produces a string like: `WU9VUl9BUElfS0VZOllPVVJfQ0xJRU5UX1NFQ1JFVA==`

### Request the token

Use your encoded credentials to obtain an access token:

<CodeGroup>
  ```bash cURL theme={null}
  curl --location --request POST 'https://api.projectcor.com/v1/oauth/token?grant_type=client_credentials' \
    --header 'Authorization: Basic YOUR_BASE64_CREDENTIALS'
  ```

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

  api_key = "YOUR_API_KEY"
  client_secret = "YOUR_CLIENT_SECRET"
  credentials = base64.b64encode(f"{api_key}:{client_secret}".encode()).decode()

  response = requests.post(
      'https://api.projectcor.com/v1/oauth/token',
      params={'grant_type': 'client_credentials'},
      headers={'Authorization': f'Basic {credentials}'}
  )

  token_data = response.json()
  access_token = token_data['access_token']
  print(f"Access token: {access_token}")
  ```

  ```javascript JavaScript theme={null}
  const apiKey = 'YOUR_API_KEY';
  const clientSecret = 'YOUR_CLIENT_SECRET';
  const credentials = btoa(`${apiKey}:${clientSecret}`);

  const response = await fetch(
    'https://api.projectcor.com/v1/oauth/token?grant_type=client_credentials',
    {
      method: 'POST',
      headers: {
        'Authorization': `Basic ${credentials}`
      }
    }
  );

  const tokenData = await response.json();
  console.log('Access token:', tokenData.access_token);
  ```
</CodeGroup>

**Success response:**

```json theme={null}
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "dGhpcyBpcyBhIHJlZnJlc2ggdG9rZW4uLi4"
}
```

<Check>
  Save the `access_token` and `refresh_token`. You'll use the access token for all API calls.
</Check>

<Tip>
  Store your tokens securely using environment variables. Never hardcode them in your source code. See [secure token management](/development#secure-token-management) for best practices.
</Tip>

### Alternative authentication methods

<Accordion title="Authorization Code Flow">
  Best for applications that act on behalf of users with their consent.

  **Step 1:** Redirect users to the consent screen:

  ```
  https://YOUR_SUBDOMAIN.cor.works/oauth2/authorize?name=YourAppName&response_type=code&redirect_uri=YOUR_CALLBACK_URL
  ```

  **Step 2:** Exchange the authorization code for a token:

  ```bash theme={null}
  curl --location --request POST 'https://api.projectcor.com/v1/oauth2/token?grant_type=authorization_code&code=AUTH_CODE'
  ```
</Accordion>

<Accordion title="User Credentials Flow">
  For testing and development purposes only.

  <Warning>
    This method is not recommended for production applications.
  </Warning>

  ```bash theme={null}
  curl --location 'https://api.projectcor.com/v1/auth/login' \
    --header 'Content-Type: application/x-www-form-urlencoded' \
    --data-urlencode 'email=your@email.com' \
    --data-urlencode 'password=your_password'
  ```
</Accordion>

***

## Step 2: Verify your authentication

Test your access token by retrieving your user profile:

<CodeGroup>
  ```bash cURL theme={null}
  curl --location 'https://api.projectcor.com/v1/me' \
    --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
  ```

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

  headers = {'Authorization': f'Bearer {access_token}'}

  response = requests.get('https://api.projectcor.com/v1/me', headers=headers)
  user = response.json()
  print(f"Logged in as: {user['first_name']} {user['last_name']}")
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch('https://api.projectcor.com/v1/me', {
    headers: {
      'Authorization': `Bearer ${accessToken}`
    }
  });

  const user = await response.json();
  console.log(`Logged in as: ${user.first_name} ${user.last_name}`);
  ```
</CodeGroup>

**Success response:**

```json theme={null}
{
  "id": 12345,
  "first_name": "John",
  "last_name": "Doe",
  "email": "john.doe@company.com",
  "picture": "https://cdn.projectcor.com/avatars/12345.jpg",
  "role_id": 3,
  "user_position_id": 5,
  "daily_hours": 8,
  "remaining_hours": 6.5,
  "cuil": null,
  "labels": []
}
```

<Note>
  Role IDs: `1` (C-Level), `2` (Director), `3` (Project Manager), `4` (Collaborator), `5` (Freelancer), `6` (Client).
</Note>

<Check>
  If you see your user data, your authentication is working correctly.
</Check>

***

## Step 3: Explore core endpoints

Now that you're authenticated, here are the most common operations you'll perform with the COR API.

### List your projects

All list endpoints in COR return **paginated responses** by default. Use `page` and `perPage` parameters to navigate results, and `filters` to narrow down the data.

<CodeGroup>
  ```bash cURL theme={null}
  # Basic request (returns page 1 with 20 items)
  curl --location 'https://api.projectcor.com/v1/projects' \
    --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'

  # With pagination
  curl --location 'https://api.projectcor.com/v1/projects?page=1&perPage=10' \
    --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'

  # With filters (URL-encoded JSON)
  curl --location 'https://api.projectcor.com/v1/projects?page=1&filters=%7B%22client_id%22%3A25855%2C%22status%22%3A%22in_process%22%2C%22archived%22%3A2%7D' \
    --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
  ```

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

  # Basic paginated request
  response = requests.get(
      'https://api.projectcor.com/v1/projects',
      params={'page': 1, 'perPage': 10},
      headers=headers
  )

  result = response.json()
  print(f"Total projects: {result['total']}")
  print(f"Page {result['page']} of {result['lastPage']}")

  for project in result['data']:
      print(f"- {project['name']} ({project['status']})")

  # With filters
  filters = json.dumps({
      "client_id": 25855,
      "status": "in_process",
      "archived": 2
  })

  response = requests.get(
      'https://api.projectcor.com/v1/projects',
      params={'page': 1, 'filters': filters},
      headers=headers
  )
  ```

  ```javascript JavaScript theme={null}
  // Basic paginated request
  const response = await fetch(
    'https://api.projectcor.com/v1/projects?page=1&perPage=10',
    { headers: { 'Authorization': `Bearer ${accessToken}` } }
  );

  const result = await response.json();
  console.log(`Total projects: ${result.total}`);
  console.log(`Page ${result.page} of ${result.lastPage}`);

  result.data.forEach(p => console.log(`- ${p.name} (${p.status})`));

  // With filters
  const filters = JSON.stringify({
    client_id: 25855,
    status: 'in_process',
    archived: 2
  });

  const filtered = await fetch(
    `https://api.projectcor.com/v1/projects?page=1&filters=${encodeURIComponent(filters)}`,
    { headers: { 'Authorization': `Bearer ${accessToken}` } }
  );
  ```
</CodeGroup>

**Paginated response structure:**

```json theme={null}
{
  "total": "14",
  "perPage": 20,
  "page": 1,
  "lastPage": 1,
  "meta_data": {
    "profitability_limit": "30.00"
  },
  "data": [
    {
      "id": 155693,
      "name": "Website Redesign",
      "brief": "Complete website overhaul for Q1",
      "client_id": 25855,
      "health": 1,
      "status": "active",
      "start": "2025-01-15 00:00:00",
      "end": "2025-03-31 00:00:00",
      "estimated_time": 200,
      "elapsed_time": 45,
      "profitability_now": 85,
      "estimated_profitability": 100,
      "archived": false,
      "billable": true,
      "income_type": "fee",
      "pm_id": 8546,
      "created_at": "2025-01-10 14:30:00",
      "client": {
        "id": 25855,
        "name": "Acme Corp",
        "client_status_id": 1
      },
      "pm": {
        "id": 8546,
        "first_name": "John",
        "last_name": "Doe",
        "email": "john@company.com",
        "role_id": 3
      }
    }
  ]
}
```

<Note>
  **Pagination parameters:**

  * `page`: Page number (default: 1). Set to `false` to disable pagination and get all results.
  * `perPage`: Items per page (default: 20).
</Note>

<Note>
  The table below lists filter fields for **GET /projects** (inside the `filters` JSON). **GET /tasks** uses different keys: use `projects` (project IDs, not `project_id`), `pm` (PM / assignee user IDs on the task, not `user_id`), and `status`, plus other task-specific fields—see [Get Tasks](/api-reference/tasks/get-tasks).
</Note>

<Accordion title="Available filter fields (GET /projects)">
  | Field        | Type   | Description                                          |
  | ------------ | ------ | ---------------------------------------------------- |
  | `dateStart`  | string | Start date range (YYYY-MM-DD)                        |
  | `dateEnd`    | string | End date range (YYYY-MM-DD)                          |
  | `client_id`  | number | Filter by client ID                                  |
  | `team_id`    | number | Filter by team ID                                    |
  | `user_id`    | number | Filter by user/PM ID                                 |
  | `brand_id`   | number | Filter by brand ID                                   |
  | `product_id` | number | Filter by product ID                                 |
  | `status`     | string | `"finished"`, `"in_process"`, `"suspended"`          |
  | `health`     | number | 1 (on track), 2 (at risk), 3 (delayed), 4 (critical) |
  | `archived`   | number | `1` (archived only), `2` (active only)               |
</Accordion>

### List tasks for a project

Tasks are also paginated by default. Use the `filters` parameter with a URL-encoded JSON object. Filter by project with the **`projects`** key (a single ID or an array of IDs), by assignee with **`pm`**, and by workflow state with **`status`**. You can also pass an optional **`order`** query parameter as URL-encoded JSON for sort hints (see the API reference).

<CodeGroup>
  ```bash cURL theme={null}
  curl --location 'https://api.projectcor.com/v1/tasks?page=1&filters=%7B%22projects%22%3A%5B5001%5D%7D' \
    --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
  ```

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

  filters = json.dumps({"projects": [5001]})

  response = requests.get(
      'https://api.projectcor.com/v1/tasks',
      params={'page': 1, 'filters': filters},
      headers=headers
  )

  result = response.json()
  print(f"Total tasks: {result['total']}")

  for task in result['data']:
      print(f"- [{task['status']}] {task['title']}")
  ```

  ```javascript JavaScript theme={null}
  const filters = JSON.stringify({ projects: [5001] });

  const response = await fetch(
    `https://api.projectcor.com/v1/tasks?page=1&filters=${encodeURIComponent(filters)}`,
    { headers: { 'Authorization': `Bearer ${accessToken}` } }
  );

  const result = await response.json();
  console.log(`Total tasks: ${result.total}`);

  result.data.forEach(t => console.log(`- [${t.status}] ${t.title}`));
  ```
</CodeGroup>

<Tip>
  The `filters` parameter accepts a URL-encoded JSON object. For tasks, common fields include `projects`, `pm`, and `status`. Send every filter inside `filters`—do not use separate query parameters like `?project_id=` or `?user_id=`.
</Tip>

**Paginated response structure:**

```json theme={null}
{
  "total": "25",
  "perPage": 20,
  "page": 1,
  "lastPage": 2,
  "data": [
    {
      "id": 10001,
      "title": "Design homepage mockup",
      "project_id": 5001,
      "description": "Create wireframes and high-fidelity mockups for the new homepage",
      "status": "finalizada",
      "priority": 2,
      "deadline": "2024-01-15T18:00:00Z",
      "archived": false
    },
    {
      "id": 10002,
      "title": "Implement responsive navigation",
      "project_id": 5001,
      "description": "Build mobile-first navigation component with hamburger menu",
      "status": "en_proceso",
      "priority": 1,
      "deadline": "2024-01-22T18:00:00Z",
      "archived": false
    }
  ]
}
```

<Note>
  Task status values: `nueva` (new), `en_proceso` (in progress), `estancada` (stalled), `finalizada` (completed).\
  Priority values: `0` (low), `1` (medium), `2` (high), `3` (urgent).
</Note>

### Log time to a task

Time entries use `start` and `stop` timestamps to track worked hours:

<CodeGroup>
  ```bash cURL theme={null}
  curl --location 'https://api.projectcor.com/v1/hours' \
    --header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
    --header 'Content-Type: application/json' \
    --data '{
      "task_log_id": 10002,
      "start": "2024-01-18T09:00:00Z",
      "stop": "2024-01-18T11:30:00Z"
    }'
  ```

  ```python Python theme={null}
  response = requests.post(
      'https://api.projectcor.com/v1/hours',
      headers={**headers, 'Content-Type': 'application/json'},
      json={
          'task_log_id': 10002,
          'start': '2024-01-18T09:00:00Z',
          'stop': '2024-01-18T11:30:00Z'
      }
  )

  print(f"Time entry created: {response.json()}")
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch('https://api.projectcor.com/v1/hours', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${accessToken}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      task_log_id: 10002,
      start: '2024-01-18T09:00:00Z',
      stop: '2024-01-18T11:30:00Z'
    })
  });

  const entry = await response.json();
  console.log('Time entry created:', entry);
  ```
</CodeGroup>

**Success response:**

```json theme={null}
{
  "id": 50001,
  "task_log_id": 10002,
  "start": "2024-01-18T09:00:00Z",
  "stop": "2024-01-18T11:30:00Z",
  "status": "pending"
}
```

<Tip>
  The `stop` field is optional. If omitted, a timer will start for the task that you can stop later.
</Tip>

### Get your clients

Clients are also paginated by default:

<CodeGroup>
  ```bash cURL theme={null}
  curl --location 'https://api.projectcor.com/v1/clients?page=1' \
    --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
  ```

  ```python Python theme={null}
  response = requests.get(
      'https://api.projectcor.com/v1/clients',
      params={'page': 1},
      headers=headers
  )

  result = response.json()
  print(f"Total clients: {result['total']}")

  for client in result['data']:
      print(f"- {client['name']} (ID: {client['id']})")
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch('https://api.projectcor.com/v1/clients?page=1', {
    headers: { 'Authorization': `Bearer ${accessToken}` }
  });

  const result = await response.json();
  console.log(`Total clients: ${result.total}`);

  result.data.forEach(c => console.log(`- ${c.name} (ID: ${c.id})`));
  ```
</CodeGroup>

**Paginated response structure:**

```json theme={null}
{
  "total": "45",
  "perPage": 20,
  "page": 1,
  "lastPage": 3,
  "data": [
    {
      "id": 2001,
      "name": "Acme Corp",
      "business_name": "Acme Corporation LLC",
      "name_contact": "Jane",
      "last_name_contact": "Smith",
      "email_contact": "jane.smith@acme.com",
      "phone": "+1 555-0100",
      "website": "https://acme.com",
      "description": "Enterprise software solutions",
      "condition": "active"
    },
    {
      "id": 2002,
      "name": "TechStart Inc",
      "business_name": "TechStart Incorporated",
      "name_contact": "Mike",
      "last_name_contact": "Johnson",
      "email_contact": "mike@techstart.io",
      "phone": "+1 555-0200",
      "website": "https://techstart.io",
      "description": "Startup accelerator",
      "condition": "active"
    }
  ]
}
```

***

## Step 4: Refresh your token

Access tokens expire after the time specified in `expires_in` (typically 1 hour). Use the refresh token to obtain a new access token:

```bash theme={null}
curl --location 'https://api.projectcor.com/v1/oauth/refreshtoken' \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'refresh_token=YOUR_REFRESH_TOKEN'
```

**Success response:**

```json theme={null}
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.newtoken...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "bmV3IHJlZnJlc2ggdG9rZW4uLi4"
}
```

<Tip>
  For production applications, implement automatic token refresh to ensure uninterrupted API access. See the [Development guide](/development#implement-automatic-token-refresh) for a complete implementation example.
</Tip>

***

## Handle errors

When something goes wrong, the API returns standard HTTP status codes:

| Code  | Description       | Solution                                 |
| ----- | ----------------- | ---------------------------------------- |
| `400` | Bad Request       | Check required fields and JSON syntax    |
| `401` | Unauthorized      | Refresh or re-obtain access token        |
| `403` | Forbidden         | Request necessary permissions from admin |
| `404` | Not Found         | Verify resource ID exists                |
| `429` | Too Many Requests | Implement backoff and retry              |
| `500` | Server Error      | Retry with exponential backoff           |

<AccordionGroup>
  <Accordion title="401 Unauthorized - Token issues">
    **Common causes:**

    * Access token has expired
    * Token not included in Authorization header
    * Token format is incorrect (missing "Bearer " prefix)

    **Solutions:**

    1. Verify header format: `Authorization: Bearer YOUR_TOKEN`
    2. Refresh the token using `/oauth/refreshtoken`
    3. Re-authenticate if refresh token is also expired
  </Accordion>

  <Accordion title="400 Bad Request - Invalid data">
    **Common causes:**

    * Missing required fields in request body
    * Invalid date format (use `YYYY-MM-DD`)
    * Malformed JSON

    **Solutions:**

    1. Check the [API Reference](/api-reference/introduction) for required parameters
    2. Validate JSON syntax before sending
    3. Ensure dates use ISO 8601 format
  </Accordion>

  <Accordion title="503 Service Unavailable">
    **Common causes:**

    * Temporary service disruption
    * High API traffic

    **Solutions:**

    1. Wait 5 minutes and retry
    2. Implement exponential backoff in your integration
    3. Check [COR Status](https://cor.zendesk.com/) for known issues
  </Accordion>
</AccordionGroup>

***

## Next steps

Congratulations! You've successfully authenticated and made your first API calls. Here's where to go next:

<CardGroup cols={2}>
  <Card title="Development Guide" icon="code" href="/development">
    Set up your development environment with best practices for token management, error handling, and pagination.
  </Card>

  <Card title="API Reference" icon="book" href="/api-reference/introduction">
    Explore all available endpoints with detailed parameters and response schemas.
  </Card>

  <Card title="Projects API" icon="folder-open" href="/api-reference/projects/get-projects">
    Create, update, and manage projects with budgets, timelines, and team assignments.
  </Card>

  <Card title="Tasks API" icon="list-check" href="/api-reference/tasks/get-tasks">
    Manage tasks, track progress, and handle assignments across your projects.
  </Card>

  <Card title="Time Tracking API" icon="clock" href="/api-reference/hours/get-hours">
    Log hours, manage time entries, and generate reports for billing.
  </Card>

  <Card title="Resource Allocation" icon="calendar-check" href="/api-reference/resource-allocation-introduction">
    Plan team capacity, allocate users to projects, and manage workload distribution.
  </Card>

  <Card title="Integrations API" icon="plug" href="/api-reference/integrations-introduction">
    Connect external systems like Salesforce, Jira, and SAP with bidirectional sync.
  </Card>
</CardGroup>

<Note>
  **Need help?** Contact our support team at [help@projectcor.com](mailto:help@projectcor.com) or visit [COR Support](https://cor.zendesk.com/).
</Note>
