---
title: "GEL admin API | Grafana Enterprise Logs documentation"
description: "Describes the GEL admin API."
---

# GEL Admin API

> **NOTE:** Admin API version v1 /admin/api/v1/ and v2 /admin/api/v2/ endpoints are deprecated and will be removed in a future release of GEL. Use the new Admin API version v3 endpoints /admin/api/v3/ instead.

It is also possible to create tenants, access policies, and tokens using the plugin.

## Tenants

A tenant is made up of the following fields:

- `name`: The machine-readable name of a tenant. It must be between 3 and 64 characters and only include the following characters, `[a-z0-9-_]`. Once set, this field is immutable.
- `display_name`: The human-readable name of a tenant. It can contain any set of characters and can be changed.
- `status`: The current status of this tenant. It can have the following values:
  
  - `active`
  - `inactive`
  - `unknown`
- `cluster`: The name of the GEL cluster to which this tenant is scoped. You can only write to or query this tenant from this cluster.

### List tenants

`GET /admin/api/v1/instances` `GET /admin/api/v2/tenants`

**Deprecated**: These endpoints are deprecated and will be removed in a future release of GEL. Use the endpoint `GET /admin/api/v3/tenants` instead.

`GET /admin/api/v3/tenants`

> Note
> 
> This endpoint only returns tenants in an `active` status. To get all tenants including `inactive` ones use the query parameter `include-non-active=true`.

Example:

console ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```console
$ curl -u :$API_TOKEN localhost:3100/admin/api/v3/tenants | jq
{
  "items": [
    {
      "name": "enterprise-logs-dev",
      "display_name": "Grafana Enterprise Logs dev tenant",
      "created_at": "2021-02-01T17:37:59.341728283Z",
      "status": "active",
      "cluster": "dev-cluster"
    }
  ],
  "type": "tenant"
}
```

### Create a tenant

`POST /admin/api/v1/instances` `POST /admin/api/v2/tenants`

**Deprecated**: these endpoints are deprecated and will be removed in a future release of GEL. Use the endpoint `POST /admin/api/v3/tenants` instead.

`POST /admin/api/v3/tenants`

Because tenant names are unique, you cannot create a new tenant with the same name as a tenant that already exists but is in the `inactive` state. Instead, to use the same tenant name again you must re-enable the `inactive` tenant by updating its state to `active`. To make this change, use the [Update Tenant](#update-tenant) endpoint. When creating a tenant via this API call, it is not required to specify the `status` field because the status is always overwritten by the API to `active`.

Example:

console ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```console
$ curl -u :$API_TOKEN localhost:3100/admin/api/v3/tenants \
--data '{"name":"dev", "display_name": "Grafana Enterprise Logs dev tenant", "cluster": "dev-cluster"}'
```

### Update tenant

`PUT /admin/api/v1/instances/{name}` `PUT /admin/api/v2/tenants/{name}`

**Deprecated**: these endpoints are deprecated and will be removed in a future release of GEL. Use the endpoint `PUT /admin/api/v3/tenants` instead.

`PUT /admin/api/v3/tenants/{name}`

Example:

console ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```console
curl -u :$API_TOKEN localhost:3100/admin/api/v3/tenants/enterprise-logs-dev \
-X PUT -H 'If-Match: "123"` \
--data '{"display_name": "Grafana Enterprise Logs dev tenant", "status": "active", "cluster": "dev-cluster"}' | jq
{
  "name": "enterprise-logs-dev",
  "display_name": "Grafana Enterprise Logs dev tenant",
  "created_at": "2021-02-01T17:37:59.341728283Z",
  "status": "active",
  "cluster": "dev-cluster"
}
```

### Read tenant details

`GET /admin/api/v1/instances/{name}` `GET /admin/api/v2/tenants/{name}`

**Deprecated**: these endpoints are deprecated and will be removed in a future release of GEL. Use the endpoint `GET /admin/api/v3/tenants/{name}` instead.

`GET /admin/api/v3/tenants/{name}`

Example:

console ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```console
$ curl -u :$API_TOKEN localhost:3100/admin/api/v3/tenants/enterprise-logs-dev | jq
{
  "name": "enterprise-logs-dev",
  "display_name": "Grafana Enterprise Logs dev tenant",
  "created_at": "2021-02-01T17:37:59.341728283Z",
  "status": "active",
  "cluster": "dev-cluster"
}
```

### Delete a tenant

`DELETE /admin/api/v1/instances/{name}` `DELETE /admin/api/v2/tenants/{name}`

**Deprecated**: these endpoints are deprecated and will be removed in a future release of GEL. In Admin API version v3, delete operations are no longer supported and have been replaced by soft deletes. Use the endpoint `PUT /admin/api/v3/tenants/{name}` with `"status": "inactive"` instead. This operation will inactivate a tenant and subsequent HTTP requests for the tenant will fail with a 401 Unauthorized HTTP status code. To re-enable a tenant, use the endpoint `PUT /admin/api/v3/tenants/{name}` with `"status": "active"`.

`PUT /admin/api/v3/tenants/{name}`

Example API call for marking a tenant inactive:

console ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```console
curl -u :$API_TOKEN localhost:3100/admin/api/v3/tenants/enterprise-logs-dev \
-X PUT -H 'If-Match: "123"` \
--data '{"status": "inactive", "cluster": "dev-cluster"}' | jq
{
  "name": "enterprise-logs-dev",
  "display_name": "Grafana Enterprise Logs dev tenant",
  "created_at": "2021-02-01T17:37:59.341728283Z",
  "status": "inactive",
  "cluster": "dev-cluster"
}
```

## Access policies

An access policy is made up of the following fields:

- `name`: The machine-readable name of a policy.
- `display_name`: The human-readable name of a tenant. It can contain any set of characters and can be changed.
- `created_at`: An [RFC3339](https://tools.ietf.org/html/rfc3339)-formatted date time.
- `realms`: A list of realms.
- `scopes`: A list of scopes.

A realm designates the tenant/cluster pairs for which the access policy allows requests:

- `tenant`: You must set this field to an existing tenant or `*`. `*`, which denotes access to all tenants.
- `cluster`: You must set this field to an existing cluster.

A scope designates what operations that the tokens, which are assigned to this access policy, are able to perform when calling the GEL API.

- `logs:read`: Permission to view data from a tenant.
- `logs:write`: Permission to write data to a tenant.
- `logs:delete`: Permission to delete data from a tenant.
- `admin`: Permission to perform admin operations.

### List access policies

`GET /admin/api/v1/accesspolicies` `GET /admin/api/v2/accesspolicies`

**Deprecated**: these endpoints are deprecated and will be removed in a future release of GEL. Use the endpoint `GET /admin/api/v3/accesspolicies` instead.

`GET /admin/api/v3/accesspolicies`

NOTES:

- This endpoint only returns access policies in an `active` status. To get all access policies including `inactive` ones use the query parameter `include-non-active=true`

Example:

console ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```console
$ curl -u :$API_TOKEN localhost:3100/admin/api/v3/accesspolicies | jq
{
  "items": [
    {
      "name": "ap1",
      "display_name": "First access policy",
      "created_at": "2021-02-01T17:37:59.341728283Z",
      "status": "active",
      "realms": [
        {
          "tenant": "enterprise-logs-dev",
          "cluster": "dev-cluster"
        }
      ],
      "scopes": [
        "logs:read",
        "logs:write"
      ]
    },
  ],
  "type": "access_policy"
}
```

### Create access policy

`POST /admin/api/v1/accesspolicies` `POST /admin/api/v2/accesspolicies`

**Deprecated**: these endpoints are deprecated and will be removed in a future release of GEL. Use the endpoint `POST /admin/api/v3/accesspolicies` instead.

`POST /admin/api/v3/accesspolicies`

Because access policy names are unique, you cannot create a new access policy with the same name as an access policy that already exists but is in the `inactive` state. Instead, to use the same access policy name again you must re-enable the `inactive` access policy by updating its state to `active`. To make this change, use the [Update Access Policy](#update-access-policy) endpoint. When creating an access policy via this API call, it is not required to specify the `status` field because the status is always overwritten by the API to `active`.

console ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```console
$ curl -u :$API_TOKEN localhost:3100/admin/api/v3/accesspolicies \
--data '{"name":"ap1", "display_name": "First access policy", \
  "created_at": "2021-02-01T17:37:59.341728283Z", \
  "realms": [{"tenant": "enterprise-logs-dev", "cluster": "dev-cluster"}], \
  "scopes": ["logs:read", "logs:write"]}'
```

### Update access policy

`PUT /admin/api/v1/accesspolicies/{name}` `PUT /admin/api/v2/accesspolicies/{name}`

**Deprecated**: these endpoints are deprecated and will be removed in a future release of GEL. Use the endpoint `PUT /admin/api/v3/accesspolicies/{name}` instead.

`PUT /admin/api/v3/accesspolicies/{name}`

Example:

console ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```console
curl -u :$API_TOKEN localhost:3100/admin/api/v3/accesspolicies/enterprise-logs-dev \
-X PUT -H 'If-Match: "123"` \
--data '{"display_name": "First access policy", \
  "status": "active", \
  "realms": [{"tenant": "enterprise-logs-dev", "cluster": "dev-cluster"}], \
  "scopes": ["logs:read", "logs:write"]}' | jq
{
  "name": "ap1",
  "display_name": "First access policy",
  "created_at": "2021-02-01T17:37:59.341728283Z",
  "status": "active",
  "realms": [
    {
      "tenant": "enterprise-logs-dev",
      "cluster": "dev-cluster"
    }
  ],
  "scopes": [
    "logs:read",
    "logs:write"
  ]
}
```

### Get access policy

`GET /admin/api/v1/accesspolicies/{name}` `GET /admin/api/v2/accesspolicies/{name}`

**Deprecated**: these endpoints are deprecated and will be removed in a future release of GEL. Use the endpoint `GET /admin/api/v3/accesspolicies/{name}` instead.

`GET /admin/api/v3/accesspolicies/{name}`

Example:

console ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```console
$ curl -u :$API_TOKEN localhost:3100/admin/api/v3/accesspolicies/ap1 | jq
{
  "name": "ap1",
  "display_name": "First access policy",
  "created_at": "2021-02-01T17:37:59.341728283Z",
  "status": "active",
  "realms": [
    {
      "tenant": "enterprise-logs-dev",
      "cluster": "dev-cluster"
    }
  ],
  "scopes": [
    "logs:read",
    "logs:write"
  ]
}
```

### Delete access policy

`DELETE /admin/api/v1/accesspolicies/{name}` `DELETE /admin/api/v2/accesspolicies/{name}`

**Deprecated**: these endpoints are deprecated and will be removed in a future release of GEL. In Admin API version v3, delete operations are no longer supported and have been replaced by soft deletes. Use the endpoint `PUT /admin/api/v3/accesspolicies/{name}` with `"status": "inactive"` instead. This operation will inactivate an access policy and subsequent HTTP requests with an associated token will fail with a 401 Unauthorized HTTP status code. To re-enable an access policy, use the endpoint `PUT /admin/api/v3/accesspolicies/{name}` with `"status": "active"`.

`PUT /admin/api/v3/accesspolicies/{name}`

Example API call for setting an access policy to inactive state:

console ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```console
curl -u :$API_TOKEN localhost:3100/admin/api/v3/accesspolicies/enterprise-logs-dev \
-X PUT -H 'If-Match: "123"` \
--data '{"status": "inactive", "display_name": "First access policy", \
  "realms": [{"tenant": "enterprise-logs-dev", "cluster": "dev-cluster"}], \
  "scopes": ["logs:read", "logs:write"]}' | jq
{
  "name": "ap1",
  "display_name": "First access policy",
  "created_at": "2021-02-01T17:37:59.341728283Z",
  "status": "inactive",
  "realms": [
    {
      "tenant": "enterprise-logs-dev",
      "cluster": "dev-cluster"
    }
  ],
  "scopes": [
    "logs:read",
    "logs:write"
  ]
}
```

## Tokens

A token is made up of the following fields:

- `name`: The machine-readable name of a policy.
- `display_name`: The human-readable name of a tenant. It can contain any set of characters and can be changed.
- `created_at`: An [RFC3339](https://tools.ietf.org/html/rfc3339)-formatted date time.
- `expiration`: An [RFC3339](https://tools.ietf.org/html/rfc3339)-formatted date time.
- `access_policy`: The name of the access policy

### Create a token

`POST /admin/api/v1/tokens` `POST /admin/api/v2/tokens`

**Deprecated**: these endpoints are deprecated and will be removed in a future release of GEL. Use the endpoint `POST /admin/api/v3/tokens` instead.

`POST /admin/api/v3/tokens`

Because token names are unique, you cannot create a new token with the same name as a token that already exists but is in the `inactive` state. Instead, to use the same token name again you must re-enable the `inactive` token by updating its state to `active`. To make this change, use the `PUT /admin/api/v3/tokens/{name}` endpoint. When creating a token via this API call, it is not required to specify the `status` field because the status is always overwritten by the API to `active`.

Example:

console ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```console
$ curl -u :$API_TOKEN localhost:3100/admin/api/v3/tokens \
--data '{"name":"devtoken", "display_name":"Dev token", \
  "created_at": "2021-02-01T17:37:59.341728283Z", \
  "expiration": "2021-03-01T17:37:59.341728283Z", \
  "access_policy": "ap1"}'
```

### Get token

`GET /admin/api/v1/tokens/{name}` `GET /admin/api/v2/tokens/{name}`

**Deprecated**: these endpoints are deprecated and will be removed in a future release of GEL. Use the endpoint `GET /admin/api/v3/tokens/{name}` instead.

`GET /admin/api/v3/tokens/{name}`

NOTES:

- The current version of the token will be returned in an `ETag` header on the response.

Example:

console ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```console
$ curl -u :$API_TOKEN localhost:3100/admin/api/v3/tokens/logs-enterprise-token | jq
{
  "name": "logs-enterprise-token",
  "display_name": "Grafana Enterprise Logs Dev Token",
  "created_at": "2021-02-01T17:37:59.341728283Z",
  "status": "active",
  "access_policy": "ap1",
  "expiration": "2021-03-01T17:37:59.341728283Z"
}
```

### Delete a token

`DELETE /admin/api/v1/tokens/{name}` `DELETE /admin/api/v2/tokens/{name}`

**Deprecated**: these endpoints are deprecated and will be removed in a future release of GEL. In Admin API version v3, delete operations are no longer supported and have been replaced by soft deletes. Use the endpoint `PUT /admin/api/v3/tokens/{name}` with `"status": "inactive"` instead. This operation will inactivate a token and subsequent HTTP requests with the token will fail with a 401 Unauthorized HTTP status code. To re-enable a token, use the endpoint `PUT /admin/api/v3/tokens/{name}` with `"status": "active"`.

`PUT /admin/api/v3/tokens/{name}`

JSON ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```json
{
  "status": "inactive"
}
```

NOTES:

- `If-Match` header matching the current version is required.

Example:

console ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```console
curl -u :$API_TOKEN localhost:8080/admin/api/v3/tokens/logs-enterprise-token \
-X PUT -H 'If-Match: "123"` \
--data '{"status": "inactive"}' | jq
{
  "name": "logs-enterprise-token",
  "display_name": "Grafana Enterprise Logs Dev Token",
  "created_at": "2021-02-01T17:37:59.341728283Z",
  "status": "inactive",
  "access_policy": "ap1",
  "expiration": "2021-03-01T17:37:59.341728283Z"
}
```

## Verify that you can write data to your GEL tenant

The following command pushes a log line by using the Loki API. The `TOKEN` environment variable contains the preceding token that was created. The value `1612951327316545500` is the current Unix epoch time in nanoseconds at the time of writing; adjust this to the current time. On Linux, you can use the `date +%s%N` command:

console ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```console
$ date +%s%N
1612951327316545500
```

Next, the timestamp is used to push a log line:

console ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```console
$ curl -u :$TOKEN localhost:3100/loki/api/v1/push \
-H "Content-Type: application/json" \
-H "X-Scope-OrdID: dev" \
--data '{"streams": [{ "stream": { "job": "example" }, "values": [ [ "1612951327316545500", "A log line" ] ] }]}'
```
