# Fetch one exam that is open for applications

- Endpoint: `GET /v1/{organizationId}/exam/{examId}`
- Production: `https://api.main-team.org/v1/{organizationId}/exam/{examId}`
- Sandbox: `https://apisnd.main-team.org/v1/{organizationId}/exam/{examId}`
- Operation: `getExam` (Exams)
- Authentication: `Authorization: Bearer <token>`, a short-lived token you sign with your API key and secret
- Permission: `exam/read:$org:$ID`

## Description

Returns one exam, in the shape `listExams` lists it, provided it is open for applications. An exam is **open for applications** while all three hold: it is not closed to applications (`preventApplication` is not `true`), its sitting (`session.date`) is still to come, and its category is active. It stops being open at the moment its sitting starts.

An exam `listExams` would not list cannot be read here either: an exam that exists but is not open answers `404`, with a message that tells it apart from an id that names no exam. Like the list, this says nothing about whether a given student may apply; `listAvailableExams` does.

A read only: nothing changes, and it is safe to repeat.

## Parameters

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `organizationId` | path | yes | string | The organization’s `_id`: 24 hexadecimal digits, as `listOrganizations` (`GET /v1/organization`) lists it. |
| `examId` | path | yes | string | The exam’s `_id`, as `listExams` lists it or as `matchedExam._id` on a leaf of `listAvailableExams` carries it. |

## Response

`200` Success: `message` is "Exam fetched successfully.".

```json
{
  "success": true,
  "message": "Exam fetched successfully.",
  "pagination": {
    "page": 1,
    "limit": 20,
    "total": 57,
    "totalPages": 3
  },
  "data": {
    "_id": "6650a1b2c3d4e5f6a7b8c9e1",
    "session": {
      "_id": "6650a1b2c3d4e5f6a7b8c9e2",
      "sessionName": "November 2026",
      "date": "2026-11-14T10:00:00.000Z",
      "startTime": "10:00",
      "tz": "global",
      "sessionAlias": "Autumn round",
      "sessionNote": "Please join ten minutes early.",
      "enableSimulation": true,
      "simulationDate": "2026-11-07T10:00:00.000Z",
      "simulationEndDate": "2026-11-08T10:00:00.000Z",
      "relatedSession": "6650a1b2c3d4e5f6a7b8c9e2",
      "createdAt": "2026-09-01T09:30:00.000Z",
      "updatedAt": "2026-09-02T14:05:00.000Z"
    },
    "category": {
      "_id": "6650a1b2c3d4e5f6a7b8c9e3",
      "name": "Mathematics",
      "altName": "Maths",
      "order": 1,
      "isActive": true,
      "nonAcceptedReplacements": [
        "6650a1b2c3d4e5f6a7b8c9ea"
      ],
      "studyMaterialLinks": [
        "https://example.org/study/mathematics"
      ],
      "createdAt": "2026-09-01T09:30:00.000Z",
      "updatedAt": "2026-09-02T14:05:00.000Z"
    },
    "language": {
      "_id": "6650a1b2c3d4e5f6a7b8c9e4",
      "name": "English",
      "code": "en",
      "order": 1,
      "createdAt": "2026-09-01T09:30:00.000Z",
      "updatedAt": "2026-09-02T14:05:00.000Z"
    },
    "grades": [
      {
        "_id": "6650a1b2c3d4e5f6a7b8c9d4",
        "name": "10",
        "createdAt": "2026-09-01T09:30:00.000Z",
        "updatedAt": "2026-09-02T14:05:00.000Z"
      }
    ],
    "countries": [
      {
        "_id": "6650a1b2c3d4e5f6a7b8c9d1",
        "name": "UNITED STATES",
        "iso3": "USA",
        "iso2": "US",
        "tz": "America/New_York",
        "dialCode": "+1",
        "flag": "🇺🇸",
        "createdAt": "2026-09-01T09:30:00.000Z",
        "updatedAt": "2026-09-02T14:05:00.000Z"
      }
    ],
    "examType": "standard",
    "examTime": 75,
    "duration": 15,
    "questionCount": 30,
    "price": 25,
    "preventApplication": false,
    "createdAt": "2026-09-01T09:30:00.000Z",
    "updatedAt": "2026-09-02T14:05:00.000Z"
  }
}
```

## Errors

| Status | Code | When |
| --- | --- | --- |
| 400 | [`bad_request`](https://hub.main-team.org/api/errors#bad_request) | `examId` is not 24 hexadecimal digits. |
| 401 | [`unauthorized`](https://hub.main-team.org/api/errors#unauthorized) | The token is missing or malformed, is not signed with your account’s `apiSecret`, breaks the `iat` and `exp` rules, has expired or been revoked, or its account is not active. All of these answer the same. |
| 403 | [`forbidden`](https://hub.main-team.org/api/errors#forbidden) | The token is valid, but no role on your account allows `exam/read` on the organization in the path, or a role denies it. |
| 404 | [`not_found`](https://hub.main-team.org/api/errors#not_found) | `organizationId` is not the `_id` of an organization. |
| 404 | [`not_found`](https://hub.main-team.org/api/errors#not_found) | No exam in the organization has this id. |
| 404 | [`not_found`](https://hub.main-team.org/api/errors#not_found) | The exam exists but is not open for applications: it is closed to applications, its sitting has started or passed, or its category is inactive. |
| 429 | [`too_many_requests`](https://hub.main-team.org/api/errors#too_many_requests) | Your account has made more than 100 requests to this operation in the current 60-second window. Wait the seconds in `Retry-After` before sending again. |
| 500 | [`internal_error`](https://hub.main-team.org/api/errors#internal_error) | Something failed on our side. Retry later, and quote `request_id` if it goes on. |

## Code samples

### curl

```bash
# $TOKEN: a short-lived token you minted with your API key and secret
curl -sS 'https://api.main-team.org/v1/<organizationId>/exam/<examId>' \
  -H "Authorization: Bearer $TOKEN"
```

### Node.js

```js
const token = process.env.TOKEN; // a short-lived token you minted with your API key and secret

const res = await fetch('https://api.main-team.org/v1/<organizationId>/exam/<examId>', {
  headers: {
    Authorization: `Bearer ${token}`,
  },
});
const body = await res.json();
if (!res.ok) throw new Error(`${res.status} ${body.error.code}: ${body.error.message}`);
console.log(body.data);
```

### PHP

```php
<?php
$token = getenv('TOKEN'); // a short-lived token you minted with your API key and secret

$ch = curl_init('https://api.main-team.org/v1/<organizationId>/exam/<examId>');
curl_setopt_array($ch, [
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . $token,
    ],
    CURLOPT_RETURNTRANSFER => true,
]);
$response = curl_exec($ch);
if ($response === false) {
    throw new RuntimeException(curl_error($ch));
}
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
$body = json_decode($response, true);
if ($status >= 400) {
    $error = $body['error'];
    throw new RuntimeException("$status {$error['code']}: {$error['message']}");
}
print_r($body['data']);
```
