# OAuth

Create, inspect, and revoke OAuth 2.0 access tokens.

## Revoke an access or refresh token

`POST /oauth/revoke`

This operation is idempotent. It returns `200 {}` whether or not the token was valid, which prevents token enumeration.

## Request body (`application/x-www-form-urlencoded`)

- `object`
  - `client_id` (`string`) - The OAuth application UID.
  - `client_secret` (`string`) - The OAuth application secret.
  - `token` (`string`) - The access or refresh token value to revoke.
  - `token_type_hint` (`string`) - enum: `access_token`, `refresh_token`; The type of token supplied in `token`.

### Example

```json
{
  "client_id": "example_client_id",
  "client_secret": "carebit_cs_live_example_client_secret",
  "token": "carebit_at_live_example_access_token",
  "token_type_hint": "access_token"
}
```

## Response `200`

The token was revoked, or was already invalid.

- `object` - An empty object returned whether or not the token was valid. This prevents token enumeration.

### Example

```json
{}
```

## Response `401`

The client credentials are invalid.

- `object`
  - `error` (`object`) - The structured details that describe why the request failed.
    - `code` (`string`) - The machine-readable error code.
    - `errors` (`array | null`) - Additional errors from a failed validation.
      - `items` (`object`)
        - `code` (`string`) - The machine-readable code for this validation error.
        - `message` (`string`) - A message that explains this validation error.
        - `param` (`string | null`) - The name of the parameter that caused this validation error, when known.
    - `message` (`string`) - A message that explains the error and how to resolve it.
    - `param` (`string | null`) - The name of the parameter that caused the error, when known.
    - `type` (`string`) - enum: `authentication_error`, `permission_error`, `invalid_request_error`, `rate_limit_error`, `api_error`; The high-level category of the error.

### Example

```json
{
  "error": {
    "code": "resource_missing",
    "errors": [
      {
        "code": "resource_missing",
        "message": "The requested resource was not found.",
        "param": "patient_id"
      }
    ],
    "message": "The requested resource was not found.",
    "param": "patient_id",
    "type": "authentication_error"
  }
}
```

## Code samples

```bash
curl -X POST "https://api.carebit.co/oauth/revoke" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  --data-urlencode "client_id=example_client_id" \
  --data-urlencode "client_secret=carebit_cs_live_example_client_secret" \
  --data-urlencode "token=carebit_at_live_example_access_token" \
  --data-urlencode "token_type_hint=access_token"
```

```javascript
const response = await fetch("https://api.carebit.co/oauth/revoke", {
  method: "POST",
  headers: {
    "Content-Type": "application/x-www-form-urlencoded",
  },
  body: new URLSearchParams({
  "client_id": "example_client_id",
  "client_secret": "carebit_cs_live_example_client_secret",
  "token": "carebit_at_live_example_access_token",
  "token_type_hint": "access_token",
}),
});

if (!response.ok) {
  throw new Error(`Carebit API error: ${response.status}`);
}

const data = await response.json();
```

```python
import os
import requests

response = requests.post(
    "https://api.carebit.co/oauth/revoke",
    data={
        "client_id": "example_client_id",
        "client_secret": "carebit_cs_live_example_client_secret",
        "token": "carebit_at_live_example_access_token",
        "token_type_hint": "access_token"
    }
)
response.raise_for_status()
data = response.json()
```

```ruby
require "httparty"

response = HTTParty.post(
  "https://api.carebit.co/oauth/revoke",
  body: {
    "client_id" => "example_client_id",
    "client_secret" => "carebit_cs_live_example_client_secret",
    "token" => "carebit_at_live_example_access_token",
    "token_type_hint" => "access_token"
  }
)
raise "Carebit API error: #{response.code}" unless response.success?
data = response.parsed_response
```

```php
<?php

$client = new GuzzleHttp\Client();

$response = $client->post("https://api.carebit.co/oauth/revoke", [
    "form_params" => [
      "client_id" => "example_client_id",
      "client_secret" => "carebit_cs_live_example_client_secret",
      "token" => "carebit_at_live_example_access_token",
      "token_type_hint" => "access_token"
    ]
]);
$data = json_decode((string) $response->getBody(), true, flags: JSON_THROW_ON_ERROR);
```


## Create an access token

`POST /oauth/token`

Exchange client credentials or a refresh token for an access token. Send `client_id` and `client_secret` using HTTP Basic authentication or as request body fields. This endpoint does not require a Bearer token; it issues one.

## Request body (`application/x-www-form-urlencoded`)

- `object`
  - `client_id` (`string`) - The OAuth application UID. Omit when passing credentials via HTTP Basic.
  - `client_secret` (`string`) - The OAuth application secret. Omit when passing credentials via HTTP Basic.
  - `grant_type` (`string`) - enum: `client_credentials`, `refresh_token`; The OAuth grant type to exchange for an access token.
  - `refresh_token` (`string`) - The refresh token issued by a previous grant. Required only for `grant_type=refresh_token`.
  - `scope` (`string`) - The space-separated list of requested scopes. Must be a subset of the developer project's scopes. Defaults to the project's full scope set for `client_credentials`. Requesting a scope the project does not have returns `invalid_scope`. Ignored for `refresh_token`.

### Example

```json
{
  "client_id": "example_client_id",
  "client_secret": "carebit_cs_live_example_client_secret",
  "grant_type": "client_credentials",
  "scope": "bookings.read bookings.create"
}
```

## Response `200`

The access token was created. The response includes a `refresh_token` for both supported grant types.

- `object`
  - `access_token` (`string`) - The issued Bearer access token.
  - `created_at` (`integer`) - The Unix timestamp at which the token was issued.
  - `expires_in` (`integer`) - The lifetime of the access token, in seconds.
  - `refresh_token` (`string`) - The refresh token. A new one is issued with each access token.
  - `scope` (`string`) - The space-separated list of granted scopes.
  - `token_type` (`string`) - The authentication scheme to use in the `Authorization` header.

### Example

```json
{
  "access_token": "carebit_at_live_example_access_token",
  "created_at": 1767193200,
  "expires_in": 3600,
  "refresh_token": "carebit_rt_live_example_refresh_token",
  "scope": "bookings.read bookings.create",
  "token_type": "Bearer"
}
```

## Response `400`

The token request is malformed, or one or more requested scopes are not on the project (`invalid_scope`).

- `object`
  - `error` (`object`) - The structured details that describe why the request failed.
    - `code` (`string`) - The machine-readable error code.
    - `errors` (`array | null`) - Additional errors from a failed validation.
      - `items` (`object`)
        - `code` (`string`) - The machine-readable code for this validation error.
        - `message` (`string`) - A message that explains this validation error.
        - `param` (`string | null`) - The name of the parameter that caused this validation error, when known.
    - `message` (`string`) - A message that explains the error and how to resolve it.
    - `param` (`string | null`) - The name of the parameter that caused the error, when known.
    - `type` (`string`) - enum: `authentication_error`, `permission_error`, `invalid_request_error`, `rate_limit_error`, `api_error`; The high-level category of the error.

### Example

```json
{
  "error": {
    "code": "resource_missing",
    "errors": [
      {
        "code": "resource_missing",
        "message": "The requested resource was not found.",
        "param": "patient_id"
      }
    ],
    "message": "The requested resource was not found.",
    "param": "patient_id",
    "type": "authentication_error"
  }
}
```

## Response `401`

The client credentials are invalid.

- `object`
  - `error` (`object`) - The structured details that describe why the request failed.
    - `code` (`string`) - The machine-readable error code.
    - `errors` (`array | null`) - Additional errors from a failed validation.
      - `items` (`object`)
        - `code` (`string`) - The machine-readable code for this validation error.
        - `message` (`string`) - A message that explains this validation error.
        - `param` (`string | null`) - The name of the parameter that caused this validation error, when known.
    - `message` (`string`) - A message that explains the error and how to resolve it.
    - `param` (`string | null`) - The name of the parameter that caused the error, when known.
    - `type` (`string`) - enum: `authentication_error`, `permission_error`, `invalid_request_error`, `rate_limit_error`, `api_error`; The high-level category of the error.

### Example

```json
{
  "error": {
    "code": "resource_missing",
    "errors": [
      {
        "code": "resource_missing",
        "message": "The requested resource was not found.",
        "param": "patient_id"
      }
    ],
    "message": "The requested resource was not found.",
    "param": "patient_id",
    "type": "authentication_error"
  }
}
```

## Response `403`

The project is disabled or archived, or the Organization does not have the developer_platform entitlement.

- `object`
  - `error` (`object`) - The structured details that describe why the request failed.
    - `code` (`string`) - The machine-readable error code.
    - `errors` (`array | null`) - Additional errors from a failed validation.
      - `items` (`object`)
        - `code` (`string`) - The machine-readable code for this validation error.
        - `message` (`string`) - A message that explains this validation error.
        - `param` (`string | null`) - The name of the parameter that caused this validation error, when known.
    - `message` (`string`) - A message that explains the error and how to resolve it.
    - `param` (`string | null`) - The name of the parameter that caused the error, when known.
    - `type` (`string`) - enum: `authentication_error`, `permission_error`, `invalid_request_error`, `rate_limit_error`, `api_error`; The high-level category of the error.

### Example

```json
{
  "error": {
    "code": "resource_missing",
    "errors": [
      {
        "code": "resource_missing",
        "message": "The requested resource was not found.",
        "param": "patient_id"
      }
    ],
    "message": "The requested resource was not found.",
    "param": "patient_id",
    "type": "authentication_error"
  }
}
```

## Response `429`

Too many token requests.

- `object`
  - `error` (`object`) - The structured details that describe why the request failed.
    - `code` (`string`) - The machine-readable error code.
    - `errors` (`array | null`) - Additional errors from a failed validation.
      - `items` (`object`)
        - `code` (`string`) - The machine-readable code for this validation error.
        - `message` (`string`) - A message that explains this validation error.
        - `param` (`string | null`) - The name of the parameter that caused this validation error, when known.
    - `message` (`string`) - A message that explains the error and how to resolve it.
    - `param` (`string | null`) - The name of the parameter that caused the error, when known.
    - `type` (`string`) - enum: `authentication_error`, `permission_error`, `invalid_request_error`, `rate_limit_error`, `api_error`; The high-level category of the error.

### Example

```json
{
  "error": {
    "code": "resource_missing",
    "errors": [
      {
        "code": "resource_missing",
        "message": "The requested resource was not found.",
        "param": "patient_id"
      }
    ],
    "message": "The requested resource was not found.",
    "param": "patient_id",
    "type": "authentication_error"
  }
}
```

## Code samples

```bash
curl -X POST "https://api.carebit.co/oauth/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  --data-urlencode "client_id=example_client_id" \
  --data-urlencode "client_secret=carebit_cs_live_example_client_secret" \
  --data-urlencode "grant_type=client_credentials" \
  --data-urlencode "scope=bookings.read bookings.create"
```

```javascript
const response = await fetch("https://api.carebit.co/oauth/token", {
  method: "POST",
  headers: {
    "Content-Type": "application/x-www-form-urlencoded",
  },
  body: new URLSearchParams({
  "client_id": "example_client_id",
  "client_secret": "carebit_cs_live_example_client_secret",
  "grant_type": "client_credentials",
  "scope": "bookings.read bookings.create",
}),
});

if (!response.ok) {
  throw new Error(`Carebit API error: ${response.status}`);
}

const data = await response.json();
```

```python
import os
import requests

response = requests.post(
    "https://api.carebit.co/oauth/token",
    data={
        "client_id": "example_client_id",
        "client_secret": "carebit_cs_live_example_client_secret",
        "grant_type": "client_credentials",
        "scope": "bookings.read bookings.create"
    }
)
response.raise_for_status()
data = response.json()
```

```ruby
require "httparty"

response = HTTParty.post(
  "https://api.carebit.co/oauth/token",
  body: {
    "client_id" => "example_client_id",
    "client_secret" => "carebit_cs_live_example_client_secret",
    "grant_type" => "client_credentials",
    "scope" => "bookings.read bookings.create"
  }
)
raise "Carebit API error: #{response.code}" unless response.success?
data = response.parsed_response
```

```php
<?php

$client = new GuzzleHttp\Client();

$response = $client->post("https://api.carebit.co/oauth/token", [
    "form_params" => [
      "client_id" => "example_client_id",
      "client_secret" => "carebit_cs_live_example_client_secret",
      "grant_type" => "client_credentials",
      "scope" => "bookings.read bookings.create"
    ]
]);
$data = json_decode((string) $response->getBody(), true, flags: JSON_THROW_ON_ERROR);
```


## Get the access token used on this request

`GET /v1/token`

Returns the current access token, the Organization and project it belongs to, and the granted scopes. Any valid access token can call this endpoint. It does not require `organization.read`. The response does not include the token secret.

## Response `200`

The requested `Token`.

- `object`
  - `created_at` (`string`) - format: `date-time`; An ISO 8601 timestamp in UTC, with a `Z` suffix. For example, `2026-07-01T09:00:00Z`.
  - `expires_at` (`string`) - format: `date-time`; The time after which this access token is no longer valid, as an ISO 8601 timestamp in UTC.
  - `id` (`string`) - format: `uuid`; The resource's unique identifier, formatted as an RFC 4122 version 4 UUID.
  - `links` (`object`) - URLs to related resources.
    - `organization` (`string`) - format: `uri`; The Organization this access token belongs to. Reading that resource requires `organization.read`.
    - `self` (`string`) - format: `uri`; This access token.
  - `livemode` (`boolean`) - `true` when the token was issued in the live Carebit environment. `false` for test tokens.
  - `object` (`any`) - Discriminator value emitted at `object`.
  - `organization` (`object`) - A summary of the Organization this access token belongs to. Address, email, and phone are omitted so a token without `organization.read` cannot read those fields.
    - `id` (`string`) - format: `uuid`; The resource's unique identifier, formatted as an RFC 4122 version 4 UUID.
    - `name` (`string`) - The display name of the Organization.
    - `object` (`any`) - Discriminator value emitted at `object`.
  - `project` (`object`) - A summary of the developer project that issued this access token.
    - `id` (`string`) - format: `uuid`; The resource's unique identifier, formatted as an RFC 4122 version 4 UUID.
    - `name` (`string`) - The display name of the developer project.
    - `object` (`any`) - Discriminator value emitted at `object`.
  - `scopes` (`array`) - The OAuth scopes granted to this access token, sorted alphabetically. This is a subset of the developer project's scopes.
    - `items` (`string`) - enum: `availability_periods.create`, `availability_periods.delete`, `availability_periods.update`, `availability_slots.read`, `bookings.cancel`, `bookings.create`, `bookings.read`, `bookings.update`, `clinician_agenda.read`, `clinicians.read`, `digital_form_responses.create`, `digital_form_responses.read`, `digital_forms.read`, `expirable_files.read`, `human_tasks.create`, `invoices.read`, `leads.create`, `leads.read`, `leads.update`, `letters.create`, `letters.read`, `lists.create`, `lists.delete`, `lists.read`, `lists.update`, `locations.read`, `notes.create`, `notes.read`, `notes.update`, `organization.read`, `organization.search`, `patient_connections.create`, `patient_connections.read`, `patient_connections.update`, `patients.create`, `patients.read`, `patients.update`, `payments.read`, `payors.create`, `payors.read`, `payors.update`, `reports.create`, `services.read`, `staff_members.read`, `test_results.create`, `test_results.read`, `transmissions.read`, `webhook_endpoints.create`, `webhook_endpoints.delete`, `webhook_endpoints.read`, `webhook_endpoints.update`; An OAuth scope granted to this access token.

### Example

```json
{
  "id": "50d3e61c-c488-42b5-850c-230f3df82fb1",
  "object": "token",
  "created_at": "2026-01-01T09:00:00Z",
  "expires_at": "2026-01-01T09:00:00Z",
  "links": {
    "organization": "https://api.carebit.co/v1/organization",
    "self": "https://api.carebit.co/v1/token"
  },
  "livemode": false,
  "organization": {
    "id": "8192a3b4-c5d6-4ef0-9123-456789abcdef",
    "object": "organization",
    "name": "Harley Street Clinic"
  },
  "project": {
    "id": "ba8dcd0b-5f84-45e2-8e82-ef825ee8db00",
    "object": "project",
    "name": "Referral portal"
  },
  "scopes": [
    "leads.create",
    "leads.read"
  ]
}
```

## Response `401`

The access token is missing, invalid, expired, or revoked.

- `object`
  - `error` (`object`) - The structured details that describe why the request failed.
    - `code` (`string`) - The machine-readable error code.
    - `errors` (`array | null`) - Additional errors from a failed validation.
      - `items` (`object`)
        - `code` (`string`) - The machine-readable code for this validation error.
        - `message` (`string`) - A message that explains this validation error.
        - `param` (`string | null`) - The name of the parameter that caused this validation error, when known.
    - `message` (`string`) - A message that explains the error and how to resolve it.
    - `param` (`string | null`) - The name of the parameter that caused the error, when known.
    - `type` (`string`) - enum: `authentication_error`, `permission_error`, `invalid_request_error`, `rate_limit_error`, `api_error`; The high-level category of the error.

### Example

```json
{
  "error": {
    "code": "resource_missing",
    "errors": [
      {
        "code": "resource_missing",
        "message": "The requested resource was not found.",
        "param": "patient_id"
      }
    ],
    "message": "The requested resource was not found.",
    "param": "patient_id",
    "type": "authentication_error"
  }
}
```

## Response `403`

The project is disabled or archived, or the Organization does not have the developer_platform entitlement.

- `object`
  - `error` (`object`) - The structured details that describe why the request failed.
    - `code` (`string`) - The machine-readable error code.
    - `errors` (`array | null`) - Additional errors from a failed validation.
      - `items` (`object`)
        - `code` (`string`) - The machine-readable code for this validation error.
        - `message` (`string`) - A message that explains this validation error.
        - `param` (`string | null`) - The name of the parameter that caused this validation error, when known.
    - `message` (`string`) - A message that explains the error and how to resolve it.
    - `param` (`string | null`) - The name of the parameter that caused the error, when known.
    - `type` (`string`) - enum: `authentication_error`, `permission_error`, `invalid_request_error`, `rate_limit_error`, `api_error`; The high-level category of the error.

### Example

```json
{
  "error": {
    "code": "resource_missing",
    "errors": [
      {
        "code": "resource_missing",
        "message": "The requested resource was not found.",
        "param": "patient_id"
      }
    ],
    "message": "The requested resource was not found.",
    "param": "patient_id",
    "type": "authentication_error"
  }
}
```

## Response `429`

Too many requests.

- `object`
  - `error` (`object`) - The structured details that describe why the request failed.
    - `code` (`string`) - The machine-readable error code.
    - `errors` (`array | null`) - Additional errors from a failed validation.
      - `items` (`object`)
        - `code` (`string`) - The machine-readable code for this validation error.
        - `message` (`string`) - A message that explains this validation error.
        - `param` (`string | null`) - The name of the parameter that caused this validation error, when known.
    - `message` (`string`) - A message that explains the error and how to resolve it.
    - `param` (`string | null`) - The name of the parameter that caused the error, when known.
    - `type` (`string`) - enum: `authentication_error`, `permission_error`, `invalid_request_error`, `rate_limit_error`, `api_error`; The high-level category of the error.

### Example

```json
{
  "error": {
    "code": "resource_missing",
    "errors": [
      {
        "code": "resource_missing",
        "message": "The requested resource was not found.",
        "param": "patient_id"
      }
    ],
    "message": "The requested resource was not found.",
    "param": "patient_id",
    "type": "authentication_error"
  }
}
```

## Code samples

```bash
curl -X GET "https://api.carebit.co/v1/token" \
  -H "Authorization: Bearer $CAREBIT_ACCESS_TOKEN"
```

```javascript
const response = await fetch("https://api.carebit.co/v1/token", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.CAREBIT_ACCESS_TOKEN}`,
  },
});

if (!response.ok) {
  throw new Error(`Carebit API error: ${response.status}`);
}

const data = await response.json();
```

```python
import os
import requests

response = requests.get(
    "https://api.carebit.co/v1/token",
    headers={
        "Authorization": f"Bearer {os.environ['CAREBIT_ACCESS_TOKEN']}",
    }
)
response.raise_for_status()
data = response.json()
```

```ruby
require "httparty"

response = HTTParty.get(
  "https://api.carebit.co/v1/token",
  headers: {
    "Authorization" => "Bearer #{ENV.fetch("CAREBIT_ACCESS_TOKEN")}"
  }
)
raise "Carebit API error: #{response.code}" unless response.success?
data = response.parsed_response
```

```php
<?php

$client = new GuzzleHttp\Client();

$response = $client->get("https://api.carebit.co/v1/token", [
    "headers" => [
      "Authorization" => "Bearer " . getenv("CAREBIT_ACCESS_TOKEN"),
    ]
]);
$data = json_decode((string) $response->getBody(), true, flags: JSON_THROW_ON_ERROR);
```

