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

# Quickstart

> Create a credential, verify connectivity, authenticate, query employees, and validate a write without persistence.

This quickstart verifies the complete integration path without requiring a persistent write.

## Prerequisites

* Access to [JobHandy Administration](https://app.jobhandy.io/admin)
* Portal permission **IT**, **HR**, or **Company-Admin** to create a key
* A dedicated API key with the required company and division scope
* A server-side runtime that can store secrets securely

<Card title="Create an API key first" icon="key" horizontal href="/get-started/api-key-management">
  Create and securely store a scoped credential before running the protected examples.
</Card>

## 1. Check public availability

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl --request GET \
  --url 'https://api.jobhandy.io/v1/health'
```

A successful response proves that the public API endpoint is reachable. It does not validate your API key, tenant scope, or access to protected resources.

## 2. Generate a request ID

Use a new UUID v4 or v7 for each logical attempt. The API echoes a supplied ID or generates one when omitted.

```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
X-Request-ID: {{requestId}}
```

`X-Request-ID` is for correlation only. It is not an idempotency key.

## 3. List employees

<CodeGroup>
  ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
  curl --request GET \
    --url 'https://api.jobhandy.io/v1/employees?page=1&pageSize=10' \
    --header 'X-API-Key: YOUR_API_KEY' \
    --header 'X-Request-ID: {{requestId}}'
  ```

  ```javascript Node.js theme={"theme":{"light":"github-light","dark":"github-dark"}}
  const requestId = crypto.randomUUID();
  const response = await fetch(
    'https://api.jobhandy.io/v1/employees?page=1&pageSize=10',
    {
      headers: {
        'X-API-Key': process.env.JOBHANDY_API_KEY,
        'X-Request-ID': requestId,
      },
    },
  );
  const payload = await response.json();
  console.log(response.status, response.headers.get('x-request-id'), payload);
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
  import os
  import uuid
  import requests

  request_id = str(uuid.uuid4())
  response = requests.get(
      'https://api.jobhandy.io/v1/employees',
      params={'page': 1, 'pageSize': 10},
      headers={
          'X-API-Key': os.environ['JOBHANDY_API_KEY'],
          'X-Request-ID': request_id,
      },
      timeout=30,
  )
  print(response.status_code, response.headers.get('X-Request-ID'))
  response.raise_for_status()
  print(response.json())
  ```

  ```powershell PowerShell theme={"theme":{"light":"github-light","dark":"github-dark"}}
  $requestId = [guid]::NewGuid().ToString()
  $headers = @{
      'X-API-Key'    = $env:JOBHANDY_API_KEY
      'X-Request-ID' = $requestId
  }
  Invoke-RestMethod `
      -Method Get `
      -Uri 'https://api.jobhandy.io/v1/employees?page=1&pageSize=10' `
      -Headers $headers
  ```
</CodeGroup>

## 4. Narrow to one tenant when required

If the key covers multiple companies, add the tenant ID returned by JobHandy resources or supplied during integration onboarding:

```http theme={"theme":{"light":"github-light","dark":"github-dark"}}
X-Tenant-ID: {{tenantId}}
```

Omit the header when you intentionally need a collection across all tenants in scope. See [Tenant scope](/concepts/tenant-scope).

## 5. Test filter quoting

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl --get 'https://api.jobhandy.io/v1/employees' \
  --header 'X-API-Key: YOUR_API_KEY' \
  --data-urlencode 'filter=lastName="van Example"'
```

The raw filter expression is URL-encoded by the HTTP client. Values containing whitespace must be quoted.

## 6. Validate a write without persistence

Use a supported write operation with `dryRun=true`. The example below validates an employee update but does not save it:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl --request PATCH \
  --url 'https://api.jobhandy.io/v1/employees/EMPLOYEE_ID?dryRun=true' \
  --header 'Content-Type: application/json' \
  --header 'X-API-Key: YOUR_API_KEY' \
  --header 'X-Request-ID: {{requestId}}' \
  --data '{"phoneNumber":"+49 221 1234567"}'
```

A successful dry run returns the projected employee. It does not reserve state; the real write can still fail if the resource changes between validation and persistence.

## 7. Recognize an error response

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "error": {
    "code": "TENANT_NOT_IN_SCOPE",
    "message": "The selected tenant is not available to this API key.",
    "requestId": "{{requestId}}"
  }
}
```

Use `error.code` for program logic, `error.message` for diagnostics, and `error.requestId` for logs and support.

## Success criteria

You have completed the quickstart when all of the following are true:

* `GET /health` returns successfully
* a protected request authenticates with your API key
* tenant selection behaves as expected for the key scope
* the response includes or echoes `X-Request-ID`
* a quoted filter returns a valid collection response
* a supported dry run returns a projection without changing data
* your logs contain no API key or unnecessary personal data

<Card title="Prepare for production" icon="clipboard-check" horizontal href="/get-started/go-live-checklist">
  Complete the security, retry, reconciliation, monitoring, and operational controls before enabling a schedule.
</Card>
