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

# Bulk Invite

> Automate candidate invitations with the API

# Bulk Invite Candidates

When you're assessing multiple candidates, you can automate invitations using the API and a simple script.

## Prerequisites

* An [API key](/guides/managing-api-keys) with admin access
* An existing assessment ID

## Basic bulk invite

Loop through a list of candidates and invite each one:

<CodeGroup>
  ```bash Bash theme={null}
  API_KEY="gai_your_key"
  ASSESSMENT_ID="your-assessment-id"

  # Invite from a list
  for email in alice@company.com bob@company.com carol@company.com; do
    name=$(echo "$email" | cut -d@ -f1 | sed 's/\./ /g')
    curl -s -X POST "https://app.trygradient.ai/api/assessments/$ASSESSMENT_ID/invite" \
      -H "Authorization: Bearer $API_KEY" \
      -H "Content-Type: application/json" \
      -d "{\"email\": \"$email\", \"name\": \"$name\"}" | jq '.inviteUrl'
  done
  ```

  ```javascript Node.js theme={null}
  const API_KEY = 'gai_your_key';
  const ASSESSMENT_ID = 'your-assessment-id';

  const candidates = [
    { email: 'alice@company.com', name: 'Alice Johnson' },
    { email: 'bob@company.com', name: 'Bob Smith' },
    { email: 'carol@company.com', name: 'Carol Davis' },
  ];

  for (const candidate of candidates) {
    const res = await fetch(
      `https://app.trygradient.ai/api/assessments/${ASSESSMENT_ID}/invite`,
      {
        method: 'POST',
        headers: {
          Authorization: `Bearer ${API_KEY}`,
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(candidate),
      }
    );
    const data = await res.json();
    console.log(`${candidate.email}: ${data.inviteUrl}`);
  }
  ```

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

  API_KEY = "gai_your_key"
  ASSESSMENT_ID = "your-assessment-id"

  candidates = [
      {"email": "alice@company.com", "name": "Alice Johnson"},
      {"email": "bob@company.com", "name": "Bob Smith"},
      {"email": "carol@company.com", "name": "Carol Davis"},
  ]

  for candidate in candidates:
      res = requests.post(
          f"https://app.trygradient.ai/api/assessments/{ASSESSMENT_ID}/invite",
          headers={"Authorization": f"Bearer {API_KEY}"},
          json=candidate,
      )
      data = res.json()
      print(f"{candidate['email']}: {data.get('inviteUrl')}")
  ```
</CodeGroup>

## Invite from CSV

For larger batches, read candidates from a CSV file:

```bash theme={null}
API_KEY="gai_your_key"
ASSESSMENT_ID="your-assessment-id"

# CSV format: name,email
tail -n +2 candidates.csv | while IFS=, read -r name email; do
  curl -s -X POST "https://app.trygradient.ai/api/assessments/$ASSESSMENT_ID/invite" \
    -H "Authorization: Bearer $API_KEY" \
    -H "Content-Type: application/json" \
    -d "{\"email\": \"$email\", \"name\": \"$name\"}"
  echo ""
done
```

## Handling duplicates

The invite endpoint is idempotent - if a candidate already has an active session for the assessment, it returns the existing session with a `200 OK` instead of creating a new one. This means you can safely re-run your invite script without creating duplicate sessions.

## Setting per-candidate deadlines

You can set individual deadlines that override the assessment-level due date:

```bash theme={null}
curl -X POST "https://app.trygradient.ai/api/assessments/$ASSESSMENT_ID/invite" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "alice@company.com",
    "name": "Alice Johnson",
    "dueDate": "2026-12-01T23:59:59Z"
  }'
```

## Monitoring progress

After inviting candidates, poll for session status to track who has completed:

```bash theme={null}
# List all sessions for this assessment
curl "https://app.trygradient.ai/api/sessions?assessmentId=$ASSESSMENT_ID" \
  -H "Authorization: Bearer $API_KEY" | jq '.sessions[] | {name: .candidateName, status: .status}'
```
