# Overview Source: https://unkey.com/docs/analytics/overview Unkey tracks everything for you Consumption based billing for APIs is getting more and more popular, but it's tedious to build in house. For low frequency events, it's quite possible to emit usage events directly to Stripe or similar, but this becomes very noisy quickly. Furthermore if you want to build end-user facing or internal analytics, you need to be able to query the events from Stripe, which often does not provide the granularity required. Most teams end up without end-user facing analytics, or build their own system to store and query usage metrics. Since Unkey already stores and aggregates verification events by time, outcome and identity, we can offer this data via an API. ## Available data Unkey stores an event for every single verification, the relevent fields are described below: | Data | Type | Explanation | | -------------- | ------------- | -------------------------------------------------------------------------------------- | | `request_id` | String | Each request has a unique id, making it possible to retrieve later. | | `time` | Int64 | A unix milli timestamp. | | `key_space_id` | String | Each workspace may have multiple key spaces. Each API you create has its own keyspace. | | `key_id` | String | The individual key being verified. | | `outcome` | String | The outcome of the verification. `VALID`, `RATE_LIMITED` etc. | | `identity_id` | String | The identity connected to this key. | | `tags` | Array(String) | Arbitrary tags you may add during the verification to filter later. | We can return this data aggregated by `hour`, `day`, `month`, `tag`, `tags`, `identity`, `key` and `outcome`. As well as filter by `identity_id`, `key_space_id`, `key_id`, `tags`, `outcome`, `start` and `end` time. ## Example For an internal dashboard you want to find the top 5 users of a specific endpoint. In order to let Unkey know about the endpoint, you specify it as a tag when verifying keys: ```bash Tagging a verification {6} curl -XPOST 'https://api.unkey.dev/v1/keys.verifyKey' \ -H 'Content-Type: application/json' \ -d '{ "key": "", "apiId": "api_", "tags": [ "path=/my/endpoint" ], }' ``` You can now query `api.unkey.dev/v1/analytics.getVerifications` via query parameters. While we can't provide raw SQL access, we wanted to stay as close to SQL semantics as possible, so you didn't need to learn a new concept and to keep the translation layer simple. | Name | Value | Explanation | | --------- | --------------------------------- | ------------------------------------------------------------------------------ | | `start` | 1733749385000 | A unix milli timestamp to limit the query to a specific time frame. | | `end` | 1736431397000 | A unix milli timestamp to limit the query to a specific time frame. | | `apiId` | api\_262b3iR7gkmP7aUyZ24uihcijsCe | The API ID to filter keys. | | `groupBy` | identity | We're not interested in individual keys, but the user/org. | | `orderBy` | total | We want to see the most active users, by how many verifications they're doing. | | `order` | desc | We're ordering from most active to least active user. | | `limit` | 5 | Only return the top 5. | Below is a curl command putting everythign together: ```bash curl 'https://api.unkey.dev/v1/analytics.getVerifications?start=1733749385000&end=1736431397000&apiId=api_262b3iR7gkmP7aUyZ24uihcijsCe&groupBy=identity&orderBy=total&order=desc&limit=5' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer ' ``` You'll receive a json response with a breakdown of each outcome, per identity ordered by `total`. ```json First Row [ { "valid": 186, "notFound": 0, "forbidden": 0, "usageExceeded": 0, "rateLimited": 184, "unauthorized": 0, "disabled": 182, "insufficientPermissions": 0, "expired": 0, "total": 552, "apiId": "api_262b3iR7gkmP7aUyZ24uihcijsCe", "identity": { "id": "test_2ipPuAgat7xuVNGpK6AuPQ2Lbk11", "externalId": "user_2rNBR4YXxKwzM8bzVrCR5q6dFlc" } }, ... ] ``` ```json Full Response [ { "valid": 186, "notFound": 0, "forbidden": 0, "usageExceeded": 0, "rateLimited": 184, "unauthorized": 0, "disabled": 182, "insufficientPermissions": 0, "expired": 0, "total": 552, "apiId": "api_262b3iR7gkmP7aUyZ24uihcijsCe", "identity": { "id": "test_2ipPuAgat7xuVNGpK6AuPQ2Lbk11", "externalId": "user_2rNBR4YXxKwzM8bzVrCR5q6dFlc" } }, { "valid": 190, "notFound": 0, "forbidden": 0, "usageExceeded": 0, "rateLimited": 161, "unauthorized": 0, "disabled": 200, "insufficientPermissions": 0, "expired": 0, "total": 551, "apiId": "api_262b3iR7gkmP7aUyZ24uihcijsCe", "identity": { "id": "test_2ipPuAiGJ3L3TUNKA6gp5eLeuyj7", "externalId": "user_2rLz6cM63ZQ2v3IU0mryKbHetjK" } }, { "valid": 197, "notFound": 0, "forbidden": 0, "usageExceeded": 0, "rateLimited": 154, "unauthorized": 0, "disabled": 200, "insufficientPermissions": 0, "expired": 0, "total": 551, "apiId": "api_262b3iR7gkmP7aUyZ24uihcijsCe", "identity": { "id": "test_2ipPuAwJVE4Hdet3dyEpYreP8ob7", "externalId": "user_2rLwFchrbyIDb4LUfFp4CpTG0L3" } }, { "valid": 191, "notFound": 0, "forbidden": 0, "usageExceeded": 0, "rateLimited": 184, "unauthorized": 0, "disabled": 171, "insufficientPermissions": 0, "expired": 0, "total": 546, "apiId": "api_262b3iR7gkmP7aUyZ24uihcijsCe", "identity": { "id": "test_2ipPuB23PVchmbkt9mMjjcpvLM8N", "externalId": "user_2rLwCGvQKtnfnemH8HTL4cxWBFo" } }, { "valid": 207, "notFound": 0, "forbidden": 0, "usageExceeded": 0, "rateLimited": 171, "unauthorized": 0, "disabled": 162, "insufficientPermissions": 0, "expired": 0, "total": 540, "apiId": "api_262b3iR7gkmP7aUyZ24uihcijsCe", "identity": { "id": "test_2ipPuApEvEAXJo9UParPL6inHLLJ", "externalId": "user_2rLDPPVfeNB2hn1ARMh2808CdwG" } } ] ``` # Quickstarts Source: https://unkey.com/docs/analytics/quickstarts Power your own dashboard, reports or usage-based billing These scenarios should give you a good starting point to understand what is possible and what you need to do. They are in no particular order and don't build upon each other. We are using cURL here for demo purposes, but you can use any of our [SDKs](/libraries) for this as well. Almost all query parameters can be combined to build powerful queries. If you run into issues or something doesn't seem possible, please get in touch, so we can figure it out together: [support@unkey.dev](mailto:support@unkey.dev) Detailed explanations about each individual parameter can be found in the [api-reference](/api-reference/analytics/get_verifications). ## User's usage over the past 24h Assuming you have an identity with `externalId=user_123` and an API with `apiId=api_123`. ```bash curl 'https://api.unkey.dev/v1/analytics.getVerifications?start=1736673687000&end=1736760087000&externalId=user_123&groupBy=hour&apiId=api_123' \ -H 'Authorization: Bearer unkey_XXX' ``` This will return 24 elements, one per hour over the last 24h. Each element tells you about the outcomes of verifications in that interval. ```json [ { "time": 1736672400000, "valid": 15125, "notFound": 0, "forbidden": 0, "usageExceeded": 1225, "rateLimited": 0, "unauthorized": 0, "disabled": 0, "insufficientPermissions": 0, "expired": 0, "total": 16350 }, { "time": 1736676000000, "valid": 765, "notFound": 0, "forbidden": 0, "usageExceeded": 0, "rateLimited": 0, "unauthorized": 0, "disabled": 0, "insufficientPermissions": 0, "expired": 0, "total": 765 }, ... 21 elements omited { "time": 1736755200000, "valid": 20016, "notFound": 0, "forbidden": 0, "usageExceeded": 0, "rateLimited": 0, "unauthorized": 0, "disabled": 0, "insufficientPermissions": 0, "expired": 51, "total": 20067 } ] ``` ## Daily usage of a user per key in the last month Assuming you have an identity with `externalId=user_123` and an API with `apiId=api_123`. ```bash curl 'https://api.unkey.dev/v1/analytics.getVerifications?start=1734168087000&end=1736760087000&externalId=user_123&groupBy=key&groupBy=day&apiId=api_123' \ -H 'Authorization: Bearer unkey_XXX' ``` This returns 1 element per active key per day and includes the keyId. ```json [ // ... { "time": 1736726400000, "valid": 13, "notFound": 0, "forbidden": 0, "usageExceeded": 0, "rateLimited": 10, "unauthorized": 0, "disabled": 0, "insufficientPermissions": 0, "expired": 0, "total": 23, "keyId": "key_2zeYsLbpULnEUsvYeFGMeJzACp4j" }, { "time": 1736726400000, "valid": 5, "notFound": 0, "forbidden": 0, "usageExceeded": 6, "rateLimited": 0, "unauthorized": 0, "disabled": 0, "insufficientPermissions": 0, "expired": 0, "total": 11, "keyId": "key_2zeViCGkJpu5zQ8G12jcBoXWy4KH" } ] ``` ## Total usage per month for an identity Assuming you have an identity with `externalId=user_123` and an API with `apiId=api_123`. You should set your `start` to the beginning of the month and `end` to now or end of the month. ```bash curl 'https://api.unkey.dev/v1/analytics.getVerifications?start=1734168087000&end=1736760087000&externalId=user_123&groupBy=month&apiId=api_123' \ -H 'Authorization: Bearer unkey_XXX' ``` This returns one element per month. ```json [ { "time": 1733011200000, "valid": 1356136098, "notFound": 0, "forbidden": 0, "usageExceeded": 0, "rateLimited": 925255, "unauthorized": 0, "disabled": 0, "insufficientPermissions": 0, "expired": 0, "total": 1357061353 } ] ``` ## Showing usage in the current billing period If you want to show a guage or similar to your user about their consumption in the current billing period. ```bash curl 'https://api.unkey.dev/v1/analytics.getVerifications?start=1734168087000&end=1736760087000&externalId=user_123&groupBy=day&apiId=api_123' \ -H 'Authorization: Bearer unkey_XXX' ``` This will return one element per day, which you can either display in a chart, or sum up to have a total value. ```json [ // ... { "time": 1736553600000, "valid": 98267, "notFound": 0, "forbidden": 0, "usageExceeded": 0, "rateLimited": 6816, "unauthorized": 0, "disabled": 0, "insufficientPermissions": 0, "expired": 0, "total": 105083 }, { "time": 1736640000000, "valid": 20125, "notFound": 0, "forbidden": 0, "usageExceeded": 0, "rateLimited": 2525, "unauthorized": 0, "disabled": 6261, "insufficientPermissions": 0, "expired": 0, "total": 28911 } ] ``` ## Internal dashboard showing top 10 users by API usage over the past 30 days ```bash curl 'https://api.unkey.dev/v1/analytics.getVerifications?start=1734168087000&end=1736760087000&orderBy=total&order=desc&limit=10&groupBy=identity&apiId=api_123' \ -H 'Authorization: Bearer unkey_XXX' ``` Returns 10 elements, ordered from most total verifications to least. Each element includes the `identityId` as well as the `externalId` for your reference. ```json [ { "identity": { "id": "id_123", "externalId": "user_123"}, "valid": 54, "notFound": 0, "forbidden": 3, "usageExceeded": 6, "rateLimited": 10, "unauthorized": 0, "disabled": 0, "insufficientPermissions": 0, "expired": 0, "total": 73 }, { "identity": { "id": "id_456", "externalId": "user_6dg"}, "valid": 24, "notFound": 0, "forbidden": 1, "usageExceeded": 32, "rateLimited": 10, "unauthorized": 0, "disabled": 0, "insufficientPermissions": 0, "expired": 0, "total": 67 }, ... ] ``` ## Filter by tags Find out how many verifications were done, where the tag `myTag` was specified. You can combine this with other parameters to group by days for example. You can provide multiple tags by providing them as separate query paramters: `?tag=myTag&tag=myOthertag`. Filtering multiple tags is a logical `OR`. The result includes all verifications where at least one of the filtered tags was specified. ```bash curl 'https://api.unkey.dev/v1/analytics.getVerifications?start=1734168087000&end=1736760087000&tag=myTag&apiId=api_123' \ -H 'Authorization: Bearer unkey_XXX' ``` This returns 1 element, a sum of all verifications in the selected time, where the tag `myTag` was specified. ```json [ { "valid": 5, "notFound": 0, "forbidden": 0, "usageExceeded": 0, "rateLimited": 0, "unauthorized": 0, "disabled": 0, "insufficientPermissions": 0, "expired": 0, "total": 5 } ] ``` ## Filter by key This only includes verifications of a specific key. You can provide multiple keyIds to filter verifications of any one of those keys. ```bash curl 'https://api.unkey.dev/v1/analytics.getVerifications?start=1734168087000&end=1736760087000&keyId=key_123&apiId=api_123' \ -H 'Authorization: Bearer unkey_XXX' ``` ```json [ { "valid": 14, "notFound": 0, "forbidden": 0, "usageExceeded": 0, "rateLimited": 10, "unauthorized": 0, "disabled": 0, "insufficientPermissions": 0, "expired": 0, "total": 24 } ] ``` ## Grouping by tags To understand usage across your tags, you can group by tags, breaking down all verifications and summing them up per tag combination. Note this is plural: `&groupBy=tags`. ```bash curl 'https://api.unkey.dev/v1/analytics.getVerifications?start=1734168087000&end=1736760087000&groupBy=tags&apiId=api_123' \ -H 'Authorization: Bearer unkey_XXX' ``` You'll receive an array of elements. Each element corresponds to one tag combination. ```json [ { "valid": 50, "notFound": 0, "forbidden": 3, "usageExceeded": 6, "rateLimited": 10, "unauthorized": 0, "disabled": 0, "insufficientPermissions": 0, "expired": 0, "total": 69, "tags": [] // these did not have tags specified }, { "valid": 1, "notFound": 0, "forbidden": 0, "usageExceeded": 0, "rateLimited": 0, "unauthorized": 0, "disabled": 0, "insufficientPermissions": 0, "expired": 0, "total": 1, "tags": [ "a", "b" ] }, { "valid": 2, "notFound": 0, "forbidden": 0, "usageExceeded": 0, "rateLimited": 0, "unauthorized": 0, "disabled": 0, "insufficientPermissions": 0, "expired": 0, "total": 2, "tags": [ "a", "c" ] }, { "valid": 2, "notFound": 0, "forbidden": 0, "usageExceeded": 0, "rateLimited": 0, "unauthorized": 0, "disabled": 0, "insufficientPermissions": 0, "expired": 0, "total": 2, "tags": [ "a" ] } ] ``` ## Breakdown by individual tag If you want to see usage for an individual tag, regardless of combination with other tags, you can group by tag. Note this is singular `&groupBy=tag`. ```bash curl 'https://api.unkey.dev/v1/analytics.getVerifications?start=1734168087000&end=1736760087000&groupBy=tag&apiId=api_123' \ -H 'Authorization: Bearer unkey_XXX' ``` You'll receive one element per unique tag. ```json [ { "valid": 1, "notFound": 0, "forbidden": 0, "usageExceeded": 0, "rateLimited": 0, "unauthorized": 0, "disabled": 0, "insufficientPermissions": 0, "expired": 0, "total": 1, "tag": "b" }, { "valid": 2, "notFound": 0, "forbidden": 0, "usageExceeded": 0, "rateLimited": 0, "unauthorized": 0, "disabled": 0, "insufficientPermissions": 0, "expired": 0, "total": 2, "tag": "c" }, { "valid": 5, "notFound": 0, "forbidden": 0, "usageExceeded": 0, "rateLimited": 0, "unauthorized": 0, "disabled": 0, "insufficientPermissions": 0, "expired": 0, "total": 5, "tag": "a" } ] ``` # Get Verifications Source: https://unkey.com/docs/api-reference/analytics/get_verifications get /v1/analytics.getVerifications To use this endpoint, your root key must have the `api.*.read_api` permission. Retrieve usage data from unkey to power your dashboards, reports or usage-based billing. ## Changelog | Date | Changes | | ----------- | ------------------- | | Jan 01 2025 | Introduced endpoint | # Create an API Source: https://unkey.com/docs/api-reference/apis/create post /v1/apis.createApi ## Changelog | Date | Changes | | ----------- | ------------------- | | Dec 06 2023 | Introduced endpoint | # Delete an API Source: https://unkey.com/docs/api-reference/apis/delete post /v1/apis.deleteApi Permanently delete an API and revoke all keys associated with it ## Changelog | Date | Changes | | ----------- | ------------------- | | Dec 06 2023 | Introduced endpoint | # Delete all keys of an API Source: https://unkey.com/docs/api-reference/apis/delete-keys post /v1/apis.deleteKeys ## Changelog | Date | Changes | | ----------- | ------------------- | | May 26 2024 | Introduced endpoint | # Retrieve an API Source: https://unkey.com/docs/api-reference/apis/get get /v1/apis.getApi ## Changelog | Date | Changes | | ----------- | ------------------- | | Dec 06 2023 | Introduced endpoint | # List keys for an API Source: https://unkey.com/docs/api-reference/apis/list-keys get /v1/apis.listKeys ## Changelog | Date | Changes | | ----------- | ----------------------------- | | Dec 06 2023 | Introduced endpoint | | May 15 2024 | Return updatedAt timestamp | | Aug 01 2024 | Return identities | | Aug 01 2024 | Added filtering by externalId | # Authentication Source: https://unkey.com/docs/api-reference/authentication How to authenticate your requests to Unkey's API You'll need to authenticate your requests to access some of the endpoints in the Unkey API. In this guide, we'll look at how authentication works. ## Bearer Token When requesting resources, you will need your root key — you will find it in the [Dashboard](https://app.unkey.com/settings/root-keys). Here's how to add the root key to the request header using cURL: ```bash curl https://api.unkey.dev/v1/... \ -H "Authorization: Bearer unkey_xxx" ``` Always keep your root key safe and reset it if you suspect it has been compromised. # BAD_REQUEST Source: https://unkey.com/docs/api-reference/errors/code/BAD_REQUEST ## Problem The request is malformed, either missing required fields, using wrong datatypes, or being syntactically incorrect. ## Solution Check the request by debugging or logging it and making sure it's correct. If that doesn't help, ask for help on [Discord](https://unkey.com/discord) # CONFLICT Source: https://unkey.com/docs/api-reference/errors/code/CONFLICT ## Problem Another resource already uses this identifier. For example workspace slugs must be unique globally. ## Solution Please choose a different name/identifier. If that doesn't help, ask for help on [Discord](https://unkey.com/discord) # DELETE_PROTECTED Source: https://unkey.com/docs/api-reference/errors/code/DELETE_PROTECTED ## Problem The resource you are trying to delete is protected and cannot be deleted. ## Solution Go to the [Unkey Dashboard](https://app.unkey.com) and remove the protection from the resource you are trying to delete. # DISABLED Source: https://unkey.com/docs/api-reference/errors/code/DISABLED ## Problem The key has been disabled. ## Solution Enable this key using the [updateKey endpoint](/api-reference/keys/update) or web interface. If that doesn't help, ask for help on [Discord](https://unkey.com/discord) # EXPIRED Source: https://unkey.com/docs/api-reference/errors/code/EXPIRED ## Problem The key has expired and can no longer be used. ## Solution Check the `expires` field and update the key if necessary. If that doesn't help, ask for help on [Discord](https://unkey.com/discord) # FORBIDDEN Source: https://unkey.com/docs/api-reference/errors/code/FORBIDDEN ## Problem We were able to authenticate you but you do not have access to the requested resources. ## Solution Use the correct key and/or double check you are requesting the correct resources. If that doesn't help, ask for help on [Discord](https://unkey.com/discord) # INSUFFICIENT_PERMISSIONS Source: https://unkey.com/docs/api-reference/errors/code/INSUFFICIENT_PERMISSIONS ## Problem You do not have permission to perform this action. In most cases this means the root key you are using, is lacking permissions. ## Solution Go to the [Unkey Dashboard](https://app.unkey.com/settings/root-keys) and add the required permissions to your key. # INTERNAL_SERVER_ERROR Source: https://unkey.com/docs/api-reference/errors/code/INTERNAL_SERVER_ERROR ## Problem Something unexpected happened and we did not handle the error well. ## Solution Please get in touch on [Discord](https://unkey.com/discord) and provide the full error response. # NOT_FOUND Source: https://unkey.com/docs/api-reference/errors/code/NOT_FOUND ## Problem The requested resource could not be found. It may have been deleted or does not exist. ## Solution Please ensure that you are providing the correct resource identifier or check if the resource has been deleted. If that doesn't help, ask for help on [Discord](https://unkey.com/discord) # TOO_MANY_REQUESTS Source: https://unkey.com/docs/api-reference/errors/code/TOO_MANY_REQUESTS ## Problem You have made too many requests in a short period of time. ## Solution Please wait a bit and try again or increase the ratelimit on your API key. If that doesn't help, ask for help on [Discord](https://unkey.com/discord) # UNAUTHORIZED Source: https://unkey.com/docs/api-reference/errors/code/UNAUTHORIZED ## Problem We were unable to authorize your request. Either your key was missing, malformed or does not have the required permissions. ## Solution Check the `message` field and double check you are sending the key correctly in the `Authorization` header. If that doesn't help, ask for help on [Discord](https://unkey.com/discord) # Introduction Source: https://unkey.com/docs/api-reference/errors/introduction Machine and human readable error codes The Unkey API returns machine readable error codes to quickly identify the type of error as well as link to the docs and a `requestId`. Please always include the `requestId` in your error report. ```json { error: { code: "UNAUTHORIZED", message: "We were unable to authorize your request. Either your key was missing, malformed or does not have the required permissions.", docs: "https://unkey.api/docs/api-reference/errors/code/BAD_REQUEST", requestId: "req_1234567890" } } ``` If you can't debug something on your own or think there is a bug, please get in touch with us on [Discord](https://unkey.com/discord) or [Email](mailto:support@unkey.dev) and provide the full error response. # Create an identity Source: https://unkey.com/docs/api-reference/identities/create-identity post /v1/identities.createIdentity Identities are in public beta. Please report any issues to [support@unkey.dev](mailto:support@unkey.dev) Create a new identity in the system. This might not be necessary as newly created keys automatically create an identity if required. Identities map your users, organisations or other entities to keys. They can be used to share metadata and limits. [Read more about identities](/concepts/identities/overview) ## Changelog | Date | Changes | | ----------- | ------------------- | | Jul 17 2024 | Introduced endpoint | # Delete an identity Source: https://unkey.com/docs/api-reference/identities/delete-identity post /v1/identities.deleteIdentity Identities are in public beta. Please report any issues to [support@unkey.dev](mailto:support@unkey.dev) Delete an identity. This will not revoke the keys associated with the identity. ## Changelog | Date | Changes | | ----------- | ------------------- | | Jul 17 2024 | Introduced endpoint | # Get an identity Source: https://unkey.com/docs/api-reference/identities/get-identity get /v1/identities.getIdentity Identities are in public beta. Please report any issues to [support@unkey.dev](mailto:support@unkey.dev) Retrieve an identity either by `identityId` or by `externalId`. The response will include the identity as well as its configured rate limits. ## Changelog | Date | Changes | | ----------- | ------------------- | | Jul 17 2024 | Introduced endpoint | # List identities Source: https://unkey.com/docs/api-reference/identities/list-identities get /v1/identities.listIdentities Identities are in public beta. Please report any issues to [support@unkey.dev](mailto:support@unkey.dev) List all identities in the system. This will return a paginated list of identities. ## Changelog | Date | Changes | | ----------- | ------------------- | | Jul 17 2024 | Introduced endpoint | # Update an identity Source: https://unkey.com/docs/api-reference/identities/update-identity post /v1/identities.updateIdentity Identities are in public beta. Please report any issues to [support@unkey.dev](mailto:support@unkey.dev) Update an identity's metadata or limits. ## Changelog | Date | Changes | | ----------- | ------------------- | | Jul 17 2024 | Introduced endpoint | # Add Permissions Source: https://unkey.com/docs/api-reference/keys/add-permissions post /v1/keys.addPermissions Add one or more permissions to a key. Adds permissions to a key. Existing permissions are not removed. To use this endpoint, your root key must have the `rbac.*.add_permission_to_key` and potentially the `rbac.*.create_permission` permissions. ## Changelog | Date | Changes | | ----------- | ------------------- | | Jul 08 2024 | Introduced endpoint | # Add Roles Source: https://unkey.com/docs/api-reference/keys/add-roles post /v1/keys.addRoles Add one or more roles to a key. Adds roles to a key. Existing roles are not removed. To use this endpoint, your root key must have the `rbac.*.add_role_to_key` and potentially the `rbac.*.create_role` permissions. ## Changelog | Date | Changes | | ----------- | ------------------- | | Jul 08 2024 | Introduced endpoint | # Create a key Source: https://unkey.com/docs/api-reference/keys/create post /v1/keys.createKey Create a new key. ## Changelog | Date | Changes | | ----------- | ------------------- | | Dec 06 2023 | Introduced endpoint | # Delete a key Source: https://unkey.com/docs/api-reference/keys/delete post /v1/keys.deleteKey Deleted keys are no longer valid and will not be able to be used to authenticate requests. ## Changelog | Date | Changes | | ----------- | ------------------- | | Dec 06 2023 | Introduced endpoint | # Retrieve a key by ID Source: https://unkey.com/docs/api-reference/keys/get get /v1/keys.getKey ## Changelog | Date | Changes | | ----------- | -------------------------- | | Dec 06 2023 | Introduced endpoint | | May 15 2024 | Return updatedAt timestamp | | Aug 01 2024 | Return identities | # Remove Permissions Source: https://unkey.com/docs/api-reference/keys/remove-permissions post /v1/keys.removePermissions Remove one or more permissions from a key. To use this endpoint, your root key must have the `rbac.*.remove_permission_from_key` permission. ## Changelog | Date | Changes | | ----------- | ------------------- | | Jul 08 2024 | Introduced endpoint | # Remove Roles Source: https://unkey.com/docs/api-reference/keys/remove-roles post /v1/keys.removeRoles Remove one or more roles from a key. To use this endpoint, your root key must have the `rbac.*.remove_role_from_key` permission. ## Changelog | Date | Changes | | ----------- | ------------------- | | Jul 08 2024 | Introduced endpoint | # Set Permissions Source: https://unkey.com/docs/api-reference/keys/set-permissions post /v1/keys.setPermissions Overwrite the permissions of a key with a new set of permissions. Sets the permissions of a key to a new set of permissions. This endpoint overwrites the existing permissions of the key with the new set. Existing permissions that are not included in the new set are removed. You can provide either permission ids or permission names in the request body. If you provide a name, we will create the permission if it does not exist. To use this endpoint, your root key must have the `rbac.*.add_permission_to_key` and potentially the `rbac.*.create_permission` permissions. ## Changelog | Date | Changes | | ----------- | ------------------- | | Jul 08 2024 | Introduced endpoint | # Set Roles Source: https://unkey.com/docs/api-reference/keys/set-roles post /v1/keys.setRoles Overwrite the roles of a key with a new set of roles. Sets the roles of a key to a new set of roles. This endpoint overwrites the existing roles of the key with the new set. Existing roles that are not included in the new set are removed. You can provide either role ids or role names in the request body. If you provide a name, we will create the role if it does not exist. To use this endpoint, your root key must have the `rbac.*.add_role_to_key` and potentially the `rbac.*.create_role` permissions. ## Changelog | Date | Changes | | ----------- | ------------------- | | Jul 08 2024 | Introduced endpoint | # Update a key Source: https://unkey.com/docs/api-reference/keys/update post /v1/keys.updateKey Updates the configuration of an existing key. Omit fields to leave unchanged. ## Changelog | Date | Changes | | ----------- | ------------------- | | Dec 06 2023 | Introduced endpoint | # Update a key's remaining limit Source: https://unkey.com/docs/api-reference/keys/update-remaining post /v1/keys.updateRemaining ## Changelog | Date | Changes | | ----------- | ------------------- | | Dec 06 2023 | Introduced endpoint | # Retrieve usage numbers Source: https://unkey.com/docs/api-reference/keys/verifications get /v1/keys.getVerifications Filter by `keyId` or `ownerId`. ## Changelog | Date | Changes | | ----------- | ------------------- | | Jan 08 2024 | Introduced endpoint | # Verify a key Source: https://unkey.com/docs/api-reference/keys/verify post /v1/keys.verifyKey ## Changelog | Date | Changes | | ----------- | -------------------- | | Dec 06 2023 | Introduced endpoint | | Jul 08 2024 | Added `EXPIRED` code | # Returns data about a key Source: https://unkey.com/docs/api-reference/keys/whoami post /v1/keys.whoami ## Changelog | Date | Changes | | ----------- | ------------------- | | Oct 07 2024 | Introduced endpoint | You may not always have easy access to the `keyId` and therefore can't use [`/v1/keys.getKey`](/api-reference/keys/get). This offers an escape hatch to send us the real key instead. # Migrate key to Unkey Source: https://unkey.com/docs/api-reference/migrations/create-keys post /v1/migrations.createKeys Add existing keys to unkey by specifying the key hash and other settings. This endpoint supports bulk inserts of up to 100 keys at a time. If you have more keys, you can call this endpoint multiple times. If any operation fails (e.g., due to a duplicate key), everything will be rolled back and no keys are created. ## Changelog | Date | Changes | | ----------- | ------------------- | | May 08 2024 | Introduced endpoint | # Overview Source: https://unkey.com/docs/api-reference/overview General information about the API. The Unkey API uses HTTP RPC-style methods and generally follow the schema: ``` https://api.unkey.dev/{version}/{service}.{method} ``` For example `GET https://api.unkey.dev/v1/apis.listKeys` to list all keys for an API. ## HTTP Methods We strictly use only `GET` and `POST` methods. `PUT` and `DELETE` are not used. ### `GET` `GET` methods are used for reading data. Filtering, sorting, or pagination is done via query parameters. ```http curl "https://api.unkey.dev/v1/keys.getKey?keyId=key_123" \ -H "Authorization: Bearer " ``` ### `POST` `POST` methods are used for creating, updating, and deleting data. Data is passed as `application/json` in the request body. ```http curl -XPOST "https://api.unkey.dev/v1/keys.createKey" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"apiId": "api_123", "name": "My Key"}' ``` # Create A Permission Source: https://unkey.com/docs/api-reference/permissions/create-permission post /v1/permissions.createPermission To use this endpoint, your root key must have the `rbac.*.create_permission` permission. ## Changelog | Date | Changes | | ----------- | ------------------- | | Jul 08 2024 | Introduced endpoint | # Create A Role Source: https://unkey.com/docs/api-reference/permissions/create-role post /v1/permissions.createRole To use this endpoint, your root key must have the `rbac.*.create_role` permission. ## Changelog | Date | Changes | | ----------- | ------------------- | | Jul 08 2024 | Introduced endpoint | # Delete A Permission Source: https://unkey.com/docs/api-reference/permissions/delete-permission post /v1/permissions.deletePermission To use this endpoint, your root key must have the `rbac.*.delete_permission` permission. ## Changelog | Date | Changes | | ----------- | ------------------- | | Jul 08 2024 | Introduced endpoint | # Delete A Role Source: https://unkey.com/docs/api-reference/permissions/delete-role post /v1/permissions.deleteRole To use this endpoint, your root key must have the `rbac.*.delete_role` permission. ## Changelog | Date | Changes | | ----------- | ------------------- | | Jul 08 2024 | Introduced endpoint | # Get Permission Source: https://unkey.com/docs/api-reference/permissions/get-permission get /v1/permissions.getPermission To use this endpoint, your root key must have the `rbac.*.read_permission` permission. ## Changelog | Date | Changes | | ----------- | ------------------- | | Jul 08 2024 | Introduced endpoint | # Get Role Source: https://unkey.com/docs/api-reference/permissions/get-role get /v1/permissions.getRole To use this endpoint, your root key must have the `rbac.*.read_role` permission. ## Changelog | Date | Changes | | ----------- | ------------------- | | Jul 08 2024 | Introduced endpoint | # List Permissions Source: https://unkey.com/docs/api-reference/permissions/list-permissions get /v1/permissions.listPermissions To use this endpoint, your root key must have the `rbac.*.read_permission` permission. ## Changelog | Date | Changes | | ----------- | ------------------- | | Jul 08 2024 | Introduced endpoint | # List Roles Source: https://unkey.com/docs/api-reference/permissions/list-roles get /v1/permissions.listRoles To use this endpoint, your root key must have the `rbac.*.read_role` permission. ## Changelog | Date | Changes | | ----------- | ------------------- | | Jul 08 2024 | Introduced endpoint | # Delete Override Source: https://unkey.com/docs/api-reference/ratelimits/delete-override post /v1/ratelimits.deleteOverride Delete an override from the system. ## Changelog | Date | Changes | | ----------- | ------------------- | | Nov 25 2024 | Introduced endpoint | # Get Override Source: https://unkey.com/docs/api-reference/ratelimits/get-override get /v1/ratelimits.getOverride Retrieve the configured override by `namespaceId` or `namespaceName`. ## Changelog | Date | Changes | | ----------- | ------------------- | | Nov 25 2024 | Introduced endpoint | # Ratelimit Source: https://unkey.com/docs/api-reference/ratelimits/limit post /v1/ratelimits.limit Ratelimit an action based on an identifier. ## Changelog | Date | Changes | | ----------- | ------------------- | | Mar 16 2024 | Introduced endpoint | # List Overrides Source: https://unkey.com/docs/api-reference/ratelimits/list-overrides get /v1/ratelimits.listOverrides Retrieve a list of configured overrides by `namespaceId` or `namespaceName`. ## Changelog | Date | Changes | | ----------- | ------------------- | | Nov 25 2024 | Introduced endpoint | # Set Override Source: https://unkey.com/docs/api-reference/ratelimits/set-override post /v1/ratelimits.setOverride Create or update an override to set specific limits for an identifier. There is no `update` endpoint. Instead you should call this endpoint again to overwrite your override. ## Changelog | Date | Changes | | ----------- | ------------------- | | Nov 25 2024 | Introduced endpoint | # Analytics Source: https://unkey.com/docs/apis/features/analytics Per key and per API analytics Unkey offers both per key and per API analytics that allow you to drive business decisions. ## Per API Analytics Our per API analytics offer a broad overview of the usage for a specific API with total keys, active keys and verifications in the last 30 days. Per API Analytics ## Per Key Analytics Our per key analytics give you a deep dive into each individual key, giving usage data, key data and where the requests originated from. This data can be useful for finding your top users, and where verifications are coming from. Per key analytics ## Tags You can add tags to verification requests to aggregate or filter data when querying. For example you might want to add the path of your API as a tag: `path=/v1/my-path` and then later retrieve a breakdown of api key usage per unique path. Unkey does not parse tags in any special way. The only limitations are: * Tags are strings. * You can specify up to 10 tags per request. * Each tag must be between (including) 1 and 128 characters. That being said, having some structure for your tags could be benefitial for you. A common theme is treating them as key-value pairs and specifying them with either a colon or equal-sign as delimiter. ``` key:value key=value ``` Since Unkey does not know what API routes your user has called or which resources they interact with, we encourage you to record these in the tags. Here's an example tags for a fictional blog API: ```json [ "path=/v1/posts.createPost", "postId=post_1asofijqknslkfqWF", "region=us-east-1", "apiVersion=f8ad21bd", // a git sha of your deployment or semver ] ``` ### Using tags Tags can be added in the request body. ```bash Providing Tags {7-10} curl --request POST \ --url https://api.unkey.dev/v1/keys.verifyKey \ --header 'Content-Type: application/json' \ --data '{ "apiId": "api_1234", "key": "sk_1234", "tags": [ "tag1", "path=/v1/my-resource/123" ] }' ``` ### Querying tags We have only rolled out tag ingestion so far to allow you to start recording data as early as possible. We're working on new query capabilities including filtering and aggregating by tags. # Example Source: https://unkey.com/docs/apis/features/authorization/example RBAC in the almost-real world Let's look at an example app for allowing your users to manage domains. As part of the API, your users will be able to perform CRUD operations against domains or individual dns records. Users of our app can have the following permissions: * `domain.delete_domain` * `domain.dns.create_record` * `domain.dns.read_record` * `domain.dns.update_record` * `domain.dns.delete_record` * `domain.create_domain` * `domain.read_domain` * `domain.update_domain` Create them in your [dashboard](https://app.unkey.com/authorization/permissions). Example permissions And we define the following roles: * `admin`: An admin can do everything * `dns.manager`: Can create, read, update and delete dns records but not access the domain itself * `read-only`: Can read domain or dns record information. Example roles Create them in your [dashboard](https://app.unkey.com/authorization/roles) too. For each role, we need to connect the permissions it should have. Go to [/app/authorization/roles](https://app.unkey.com/authorization/roles) and click on the role to go to the permissions screen. Admin roles dns.manager roles read-only roles Now that we have permissions and roles in place, we can connect them to keys. 1. In the sidebar, click on one of your APIs 2. Then click on `Keys` in the tabs 3. Select one of your existing keys by clicking on it 4. Go to the `Permissions` tab You should now be on `/app/keys/key_auth_???/key_???/permissions` Unconnected roles and permissions You can connect a role to your key by clicking on the checkbox in the graph. Let's give this key the `dns.manager` and `read-only` roles. Connected roles and permissions As you can see, now the key is connected to the following permissions: `domain.dns.create_record`, `domain.dns.read_record`, `domain.dns.update_record`, `domain.dns.delete_record`, `domain.create_domain`, `domain.read_domain` You can attach roles to a key when creating it by providing the role names as an array: ```bash curl -XPOST \ --url https://api.unkey.dev/v1/keys.createKey \ -H "Authorization: Bearer ${ROOT_KEY}" \ -H "Content-Type: application/json" \ -d '{ "apiId": "${API_ID}", "roles": [ "role1", "role2", "role3" ] }' ``` See [here](/api-reference/keys/create) for details. Now you can verify this key and perform permission checks. [Read more](/apis/features/authorization/verifying) # Overview Source: https://unkey.com/docs/apis/features/authorization/introduction Access Control with Roles and Permissions Role-Based Access Control (RBAC) is a security paradigm that restricts system access to authorized actors. It is based on the principle of assigning roles to actors and defining what actions or resources each role can access. We are taking this one step further and allowing you to attach arbitrary permissions to keys, for more flexibility (Coming in Q2). # Roles and Permissions Source: https://unkey.com/docs/apis/features/authorization/roles-and-permissions In RBAC, roles represent a collection of permissions. Each role defines a set of actions or operations that a user with that role can perform. Permissions can be associated with various resources within your application, such as endpoints, data objects, or functionality. Common roles may include: * `Administrator`: Has full access to all resources and functionality. * `Editor`: Can create, read, update, and delete specific resources. * `Viewer`: Can only view resources but cannot modify them. ## Roles Creating, updating and deleting roles is available in the dashboard. ### Create 1. Go to [/app/authorization/roles](https://app.unkey.com/authorization/roles) 2. Click `Create New Role` 3. Enter a unique name for your role and optionally a human readable description. 4. Click `Create` After the role is created, you are forwarded and can update/delete the role or connect existing permissions. ### Update 1. Go to [/app/authorization/roles](https://app.unkey.com/authorization/roles) 2. Click on the role you want to update 3. Click `Update Role` 4. Make changes to the name, description or both 5. Click `Save` ### Delete 1. Go to [/app/authorization/roles](https://app.unkey.com/authorization/roles) 2. Click on the role you want to delete 3. Click `Delete Role` 4. Enter the name of the role to confirm 5. Click `Delete Role` ## Permissions Creating, updating and deleting permissions is available in the dashboard. ### Create 1. Go to [/app/authorization/permissions](https://app.unkey.com/authorization/permissions) 2. Click `Create New Permission` 3. Enter a unique name for your permissoin and optionally a human readable description. 4. Click `Create New Permission` ### Update 1. Go to [/app/authorization/permissions](https://app.unkey.com/authorization/permissions) 2. Click on the permission you want to update 3. Click `Update Role` 4. Make changes to the name, description or both 5. Click `Save` ### Delete 1. Go to [/app/authorization/permisions](https://app.unkey.com/authorization/permisions) 2. Click on the permission you want to delete 3. Click `Delete` 4. Enter the name of the permission to confirm 5. Click `Delete` ## Connecting roles and permissions After you have created at least 1 role and 1 permission, you can start associating them with each other. Go to [/app/authorization/roles](https://app.unkey.com/authorization/roles) and click on the role to go to the permissions screen. Now you can click the checkboxes to connect the role and permission. A checked box means the role will grant the permission to keys. Read-only roles ## Connecting roles to keys 1. In the sidebar, click on one of your APIs 2. Then click on `Keys` in the tabs 3. Select one of your existing keys by clicking on it 4. Go to the `Permissions` tab You should now be on `/app/keys/key_auth_???/key_???/permissions` Unconnected roles and permissions You can connect a role to your key by clicking on the checkbox in the graph. Let's give this key the `dns.manager` and `read-only` roles. Connected roles and permissions As you can see, now the key is connected to the following permissions: `domain.dns.create_record`, `domain.dns.read_record`, `domain.dns.update_record`, `domain.dns.delete_record`, `domain.create_domain`, `domain.read_domain` ## Creating keys When a user of your app creates a new key, you can attach zero, one or multiple previously created roles to the key. ```bash curl -XPOST \ --url https://api.unkey.dev/v1/keys.createKey \ -H "Authorization: Bearer ${ROOT_KEY}" \ -H "Content-Type: application/json" \ -d '{ "apiId": "${API_ID}", "roles": [ "role1", "role2", "role3" ] }' ``` See [here](/api-reference/keys/create) for details. # Verifying Source: https://unkey.com/docs/apis/features/authorization/verifying Verifying permissions through the API Once a key is generated, you can verify it using the [verify](/api-reference/keys/verify) endpoint. Our system verifies whether the key has the necessary permissions to perform the requested action(s). If the user's role grants the required permissions, the request is allowed to proceed; otherwise, access is denied. This will return valid if the key has the permission: `admin` ```bash Single Permission curl --request POST \ --url https://api.unkey.dev/v1/keys.verifyKey \ --header 'Content-Type: application/json' \ --data '{ "apiId": "api_1234", "key": "sk_1234", "authorization": { "permissions": "admin" } }' ``` This will return valid if the key has either `admin` or both `dns.record.read` and `dns.record.update` permissions. ```bash Nested Query curl --request POST \ --url https://api.unkey.dev/v1/keys.verifyKey \ --header 'Content-Type: application/json' \ --data '{ "apiId": "api_1234", "key": "sk_1234", "authorization": { "permissions": { "or": [ "admin", { "and": [ "dns.record.read", "dns.record.update" ] } ] } } }' ``` Sometimes you just don't know what permissions are required before loading resources from your database. In these cases you can manually check permissions as well. Verify the key and all permissions that you already know before needing to query your database. If the response is invalid, you can return early. The key is at least valid, so you can query our database to fetch more information. The verification response from step 1 includes all permissions attached to the keys and looks something like this: ```json { valid: true, permissions: ["permission1", "permission2", ...] //... omited for brevity } ``` Use the attached permissions and the context loaded from your database to determine if you should proceed handling the request or returning an authorization error. # Disabling Keys Source: https://unkey.com/docs/apis/features/enabled Enable or disable a key. Disabled keys will not validate. This feature is useful for disabling a key temporarily. While disabled the key will act as an invalid key. Example: Suppose you have a customer that has not paid their bill. You may not want to delete the key and wait for the account balance to be current. The key can be disabled temporarily, preventing access until it is enabled. Unkey allows you to disable a key on an individual basis. ### Example Let's disable a key temperarily blocking access with that key. ```bash curl --request POST \ --url https://api.unkey.dev/v1/keys.updateKey \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "enabled": false, "keyId": "" }' ``` Now, when you verify the updated key it will show as invalid. ```bash curl --request POST \ --url https://api.unkey.dev/v1/keys.verifyKey \ --header 'Content-Type: application/json' \ --data '{ "key": "" }' ``` ```json { "keyId": "", "valid": false, "meta": {}, "enabled": false } ``` The returned `enabled` value can be changed with the updateKey endpoint to re-enable the key. # Environments Source: https://unkey.com/docs/apis/features/environments Separate your keys into live and test environments. For many applications it's useful to provide keys for developing and testing to your users. They can not interact with real production resources and may have lower ratelimits but use the exact same flow as your `live` keys. Unkey allows you to set an arbitrary value as `environment` for each key, so you can model your domain however you want. In practice we often see two distinct environments being used a lot: * `live` Live keys are used in production and affect real resources. * `test` Test keys allow you to develop and test your code without modifying real resources. It's great to ensure your code is working manually or can be used in automated tests. You may also want to associate different ratelimits per environment or bill usage differently. Perhaps test keys have lower limits but are free to use. ### Creating a key with an environment Using the prefix to indicate the environment is optional but highly recommended. It can prevent your user from accidentally using keys interchangably and modifying resources unintentionally. ```bash Test curl --request POST \ --url https://api.unkey.dev/v1/keys.createKey \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "environment": "test", "prefix": "sk_test" }' ``` ```bash Live curl --request POST \ --url https://api.unkey.dev/v1/keys.createKey \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "environment": "live", "prefix": "sk_live" }' ``` For more details, see the [API reference](/api-reference/keys/create) ### Verifying a key When you are using different environments, you obviously need a way to know what environment the used key is in. We provide this as part of the verification response: ```bash curl --request POST \ --url https://api.unkey.dev/v1/keys.verifyKey \ --header 'Content-Type: application/json' \ --data '{ "apiId": "api_1234", "key": "sk_1234" }' ``` The response would look something like this: ```json { "valid": true, "environment": "test", // ... omited } ``` # Modes Source: https://unkey.com/docs/apis/features/ratelimiting/modes Latency or consistency? Choose the right mode for your usecase. Unkey offers `fixed window` rate limiting out of the box for all API keys. This means that you can set a limit on how many requests a key can make in a given time window. If the limit is exceeded, the key will be blocked from making further requests until the window resets. We provide 2 ways of rate limiting, optimized for different usecases. ## Local, fast rate limiting at the edge API key validation is very sensitive to latency because it is in the critical path of your application. Therefore minimizing the latency impact of rate limiting is a key priority. Rate limiting at the edge comes with no latency increase and effectively rate limits your users at each edge location. To make this possible, each edge location maintains their own rate limiting and updates with the global state asynchronously, thus a user could exceed your rate limit if they go through different edge locations. This way of limiting is effective to protect your application because there is a guaranteed upper bound after all edge locations the user is accessing have reached their limit. ### Example ```bash curl --request POST \ --url https://api.unkey.dev/v1/keys.createKey \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "apiId":"", "prefix":"xyz", "byteLength":16, "ownerId":"", "ratelimit":{ "async": true, // edge rate limiting "limit": 10, "duration": 1000 } }' ``` ## Global consensus rate limiting If having a strict rate limit that must not be exceeded, even when verifying keys in multiple regions, is required, then this is a good option. This way of limiting is guaranteed to be consistent globally, but it comes with a higher latency impact. Typically most of your traffic should pass, and we recommend using the local rate limiting to provide a better user experience and only use global rate limiting when you really need to. ### Example ```bash curl --request POST \ --url https://api.unkey.dev/v1/keys.createKey \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "apiId":"", "prefix":"xyz", "byteLength":16, "ownerId":"", "ratelimit":{ "async": false, // origin rate limiting "limit":10, "duration": 1000 } }' ``` # Overview Source: https://unkey.com/docs/apis/features/ratelimiting/overview How rate limiting works in unkey Ratelimits are a way to control the amount of requests a key can make in a given timeframe. This is useful to prevent abuse and to protect your API from being overwhelmed. The field `ratelimit` is deprecated. Please use `ratelimits` instead. Ratelimits are configured on a per-key or per-identity basis and can be managed through the dashboard or the API. In order to use a ratelimiting when verifying a key, you need to specify at least the name. ```json { // ... "ratelimits": [ { "name": "my-ratelimit", } ] ``` If you do not specify at least one ratelimit, the request will not get ratelimited. As part of the migration towards the new ratelimiting system, there is a magic ratelimit called `default` that will be applied to all requests automatically. The default ratelimit is the one you have previously configured on the key itself. If you want to disable this, please got to the key's settings and delete the limit or use the [updateKey endpoint](https://www.unkey.com/docs/api-reference/keys/update) # Refill Source: https://unkey.com/docs/apis/features/refill Refill remaining key verifications on a set interval This feature is useful for creating an API key that automatically refills daily or monthly. Daily refills trigger each night at midnight, while monthly refills are triggered on the first day of each month. Example: Suppose you are selling API access, and a customer has purchased 1000 API uses per month. On the first day of the month, the 1000 uses will be refilled for that key. Unkey allows you to set a refill interval and increment on individual keys, and we take care of refilling a key on its set interval. ### Example Let's create a new key that can be used 100 times a day. ```bash curl --request POST \ --url https://api.unkey.dev/v1/keys.createKey \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "apiId":"", "remaining": 100, "refill": { "interval": "daily", "amount": 100 } }' ``` Now, when you verify the new key, you will receive the remaining verifications. After all of them are used up, the key becomes invalid. ```bash curl --request POST \ --url https://api.unkey.dev/v1/keys.verifyKey \ --header 'Content-Type: application/json' \ --data '{ "key": "" }' ``` ```json { "keyId": "", "valid": true, "meta": {}, "remaining": 99 } ``` The returned `remaining` value represents how many verifications are remaining after the current one. A value of 3, means you can verify the key successfully 3 more times. # Usage limited keys Source: https://unkey.com/docs/apis/features/remaining Limiting the usage of keys Sometimes you would like to create an api key and automatically invalidate it after a certain number of uses. Example: You are selling API access and a customer has purchased 1000 api requests from you. Unkey allows you to set/update usage limits on individual keys and we take care of invalidating a key after it has reached its limit. ### Example Let's create a new key, which can be used 100 times. ```bash curl --request POST \ --url https://api.unkey.dev/v1/keys.createKey \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "apiId":"", "remaining": 100 }' ``` Now when you verify the new key, you will receive back the remaining verifications and after all of them are used up, the key is invalid. ```bash curl --request POST \ --url https://api.unkey.dev/v1/keys.verifyKey \ --header 'Content-Type: application/json' \ --data '{ "apiId":"", "key": "" }' ``` ```json { "valid": true, "remaining": 99 } ``` The returned `remaining` value represents how many verifications are remaining after the current one. A value of 3, means you can verify the key successfully 3 more times. ## Custom cost By default we deduct `1` from the remaining verifications, but in some cases you need to deduct more. You can override this in the request body. In this example unkey would deduct `4` for every valid verification. If a key would only have 3 remaining, the request would be rejected, as there is not enough remaining left. There is a special case when you set `cost = 0`. In this case, the request will always be valid, but will not deduct anything. ```bash {7-9} curl --request POST \ --url https://api.unkey.dev/v1/keys.verifyKey \ --header 'Content-Type: application/json' \ --data '{ "apiId":"", "key": "", "remaining": { "cost": 4 } }' ``` # Key Revocation Source: https://unkey.com/docs/apis/features/revocation Keys can be revoked at any time, from the API or the dashboard. In the event that a key is compromised, you can revoke it at any time. Once the key is revoked, it can take up to 60 seconds for the key to be invalidated. Once invalidated, the key will no longer be able to be used to authenticate requests. # Temporary Keys Source: https://unkey.com/docs/apis/features/temp-keys How to create temporary API Keys in Unkey ## What are temporary API Keys? Temporary API Keys are API Keys that expire after a certain amount of time. They are useful for when you want to give a user access to your API for a limited amount of time. For example, you might want to give a user access to your API for 1 hour, or 1 day, or 1 week. You can do this by creating a temporary API Key that expires after a certain amount of time. ## How to create a temporary API Key To create a temporary API Key, you need to make a `POST` request to the `/v1/keys` endpoint. You can read about all the parameters you can send in the [API Reference](/api-reference/keys/create). ```bash curl --request POST \ --url https://api.unkey.dev/v1/keys.createKey \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "apiId":"", "prefix":"xyz", "byteLength":16, "ownerId":"USER_ID", "expires": 1718718673000, }' ``` Once the key is created, you can send it to your user. They can then use it to access your API. Once the key expires, they will no longer be able to access your API and the key will be deleted. # IP Whitelisting Source: https://unkey.com/docs/apis/features/whitelist Unkey offers IP whitelisting to restrict requests to a specific set of IP addresses. This is useful for restricting access to your API to a specific set of IP addresses, such as your own servers or a set of trusted partners. This feature is available as an addon or with an Enterprise plan. IP Whitelist example # Overview Source: https://unkey.com/docs/apis/introduction Protect your public APIs Unkey provides a simple feature rich API key management system. You can use Unkey to protect your public APIs with ease. Below is an example of implementing Unkey in your API. ```ts Typescript import { verifyKey } from '@unkey/api'; const { result, error } = await verifyKey({ apiId: "api_123", key: "xyz_123" }) if ( error ) { // handle network error } if ( !result.valid ) { // reject unauthorized request } ``` ```py Python import asyncio import os import unkey async def main() -> None: client = unkey.Client(api_key=os.environ["API_KEY"]) await client.start() result = await client.keys.verify_key("prefix_abc123") if result.is_ok: print(data.valid) else: print(result.unwrap_err()) ``` ```go Golang package main import ( "fmt" unkey "github.com/WilfredAlmeida/unkey-go/features" ) func main() { apiKey := "key_3ZZ7faUrkfv1YAhffAcnKW74" response, err := unkey.KeyVerify(apiKey) if err != nil { fmt.Println("Error:", err) return } if response.Valid { fmt.Println("Key is valid") } else { fmt.Println("Key is invalid") } } ``` ```bash cURL curl --request POST \ --url https://api.unkey.dev/v1/keys.verifyKey \ --header 'Content-Type: application/json' \ --data '{ "apiId": "api_1234", "key": "sk_1234" }' ``` ## Features Below are some of the key features of Unkey API key management system, for you to explore. Key based ratelimiting Set usage limits per key Keys that expire after a set time Refill your remaining keys on a set schedule Rich analytics on your API and keys Separate your keys into live and test environments Access Control with Roles and Permissions # Overview Source: https://unkey.com/docs/audit-log/introduction Audit logs for your workspace, allowing you to see the history of all the resource requests made inside your workspace. We automatically capture all mutations, including key creation, permission changes and configuration changes. ## Accessing Audit Logs To access the Audit Logs, click [here](https://app.unkey.com/audit) or on the **Audit Logs** option in the left navigation bar. # Audit logs in detail The audit logs table displays the following fields: * **Actor**: who was responsible for the change. This can be either a user (for actions taken in the web app) or a key (for actions taken via the API). * **Event**: the type of change. You can filter by type of events using the UI. Click to expand for more detail. * **Location**: the IP address of the actor who made the change. # Feature requests Need additional functionality from audit logs, beyond what is provided currently? [Get in touch](mailto:support@unkey.dev)! # Event Types Source: https://unkey.com/docs/audit-log/types Available audit log event types ## Workspaces Workspace actions that will create a new audit log item. * `workspace.create` - A workspace is created. * `workspace.update` - A workspace is updated. ## API API actions that will create a new audit log item. * `api.create` - An API is created. * `api.update` - An API is updated. * `api.delete` - An API is deleted. ## Keys Key actions that will create a new audit log item. * `key.create` - A key is created. * `key.update` - A key is updated. * `key.delete` - A key is deleted. ## Ratelimit Ratelimit actions that will create a new audit log item. ### Ratelimit Namespace * `ratelimitNamespace.update` - A ratelimit namespace is updated. * `ratelimitNamespace.update` - A ratelimit namespace is updated. * `ratelimitNamespace.delete` - A ratelimit namespace is deleted. ### Ratelimit Override * `ratelimitOverride.create` - A ratelimit override is created. * `ratelimitOverride.update` - A ratelimit override is updated. ## Role Role actions that will create a new audit log item. * `role.create` - A role is created. * `role.update` - A role is updated. * `role.delete` - A role is deleted. ## Permission Permission actions that will create a new audit log item. * `permission.create` - A permission is created. * `permission.update` - A permission is updated. * `permission.delete` - A permission is deleted. ## Authorization Authorization actions that will create a new audit log item. * `authorization.connect_role_and_permission` - A role and permission are connected * `authorization.disconnect_role_and_permissions` - A role and permission are disconnected. * `authorization.connect_role_and_key` - A role and key are connected. * `authorization.disconnect_role_and_key` - A role and key are disconnected. * `authorization.connect_permission_and_key` - A permission and key are connected. * `authorization.disconnect_permission_and_key` - A permission and key are disconnected. # Overview Source: https://unkey.com/docs/concepts/identities/overview Identities are a representations of a user, an org or a machine in your application. Identities are in in public beta, please report any issues you encounter: [support](mailto:support@unkey.dev). Identities are used to map your users, organizations, or even machine-users in Unkey and allow you to share metadata and configuration across multiple keys. An identity is directly linked via a unique identifier from your system and you can associate as many keys as you want with an identity. ## Use cases ### Multiple keys for the same user It is very common to issue multiple keys for the same user, but managing metadata and configuration for each key can be cumbersome and error-prone. By associating all keys with the same identity, you can share metadata and configuration across all keys. Instead of updating each key, you can update the identity and all keys associated with it will automatically get the updated metadata and configuration. ### Sharing ratelimits across multiple keys If you have multiple keys for the same user, you can set ratelimits for the identity and share it across all keys. This way, you can ensure that the user does not exceed the ratelimits across all of their keys. [Read more](/concepts/identities/ratelimits) about how to share ratelimits across multiple keys. ### Aggregated analytics If you are building a multi-tenant product, you can associate all keys of an organization with the organization's identity. This way, you can aggregate analytics across all keys of the organization and provide insights to the organization admin or drive your billing. ## Data model The unique identifier of the identity in Unkey. You may use this to reference the identity in other API calls. The id of the identity in your system. This is used to link the identity in Unkey to your system. For example your user id, or organization id if you are linking an organization. If you are using a 3rd party auth provider like Clerk, WorkOS, or Auth0, they will provide you a unique id for users and organizations. This is what you should use as the externalId. We want to build deeper integrations with them, so if you are using one of these, please let us know so we can prioritize it. A JSON object that can store any additional information about the identity. We do not make assumptions about this data, it's entirely up to you to decide what to store here. # Ratelimits Source: https://unkey.com/docs/concepts/identities/ratelimits Identities can be used to share ratelimits across multiple keys Identities are in in public beta, please report any issues you encounter: [support](mailto:support@unkey.dev). ## Sharing ratelimits Identities allow you to share ratelimits across multiple keys. Let's say you want to limit a specific user to 100 requests per second: If you just set each key to `100 RPS` then the user can make `100 * number of keys` requests per second, which probably isn't what you want. Of course you could limit the number of keys a user can have or do some math to divide 100 by the number of keys they have, but that's not fixing the actual problem, it's just a workaround. Instead, you should create an identity for the user, set the ratelimit on the identity to `100 RPS` and then associate all keys of the user with the identity. This way, the user can only make `100 RPS` across all of their keys. ## Multiple ratelimits You can set multiple ratelimits for an identity and check against some or all of them when verifying a key. Let's say you are building an app that uses AI under the hood and you want to limit your customers to 500 requests per hour, but also ensure that they don't blow up your bill by using too many tokens. In this case you would create an identity for the user and then create two ratelimits: 1. `{name: "requests", limit: 500, duration: 3600000}` -> 500 requests per hour 2. `{name: "tokens", limit: 20000, duration: 86400000}` -> 20k tokens per day Now if either one of those limits is exceeded, the request is denied. API reference for verifying: [/api-reference/keys/verify](https://www.unkey.com/docs/api-reference/keys/verify) API reference for creating identities: [/api-reference/identities/create-identity](https://www.unkey.com/docs/api-reference/identities/create-identity) # Editor Setup (Optional) Source: https://unkey.com/docs/contributing/editor-setup Editor setup to enhance your development experience # Visual Studio Code Here is a list of recommended VS Code extensions: * [Biome](https://marketplace.visualstudio.com/items?itemName=biomejs.biome) - Linter and code formatter To configure Biome as the default formatter for supported files in this workspace, follow these steps: 1. Open the `.vscode/settings.json` file. 2. Add or update the settings to set Biome as the default formatter for various file types: ```json { "[jsonc]": { "editor.defaultFormatter": "biomejs.biome" }, "[json]": { "editor.defaultFormatter": "biomejs.biome" }, "[javascript]": { "editor.defaultFormatter": "biomejs.biome" }, "[typescript]": { "editor.defaultFormatter": "biomejs.biome" }, "[typescriptreact]": { "editor.defaultFormatter": "biomejs.biome" }, "editor.codeActionsOnSave": { "source.organizeImports.biome": true, "quickfix.biome": true } } ``` For detailed information about the Biome extension and its features, visit the [Biome Documentation](https://biomejs.dev/reference/vscode/). # null Source: https://unkey.com/docs/contributing/getting-started ### Services You need the following services to run Unkey: * [Clerk](https://clerk.com?ref=unkey): Authentication You also need the following tools installed. * [Node](https://nodejs.org) * [pnpm](https://pnpm.io/installation) * [Docker](https://www.docker.com/products/docker-desktop) ### Web Application / Marketing Site Get the repo [here.](https://github.com/unkeyed/unkey) ```bash git clone https://github.com/unkeyed/unkey ``` ```bash cd unkey corepack enable pnpm install ``` Unkey provides a CLI to setup our local development environment. Run the following command in your terminal: ```bash pnpm local ``` Docker must be running for us to spin up the database. You will be prompted to enter the following values: * `CLERK_SECRET_KEY`: Your Clerk secret key. * `NEXT_PUBLIC_CLERK_PUBLIC_KEY`: Your Clerk public key. We will create `.env` files in either the `apps/dashboard` or `apps/www` depending on the selection you've made. ### API You do not need this if you are just working on the web app. The API runs on `workerd`, thus you need to populate `apps/api/.dev.vars` instead of `.env` with the same values as above. ``` DATABASE_HOST=aws.connect.psdb.cloud DATABASE_USERNAME=... DATABASE_PASSWORD=pscale_pw_.... ``` #### Running the API ```bash cd apps/api pnpm dev ``` The development server runs on `:8787` by default. ### About pnpm local command If you have already set up Unkey locally once and wish to bypass the manual input questions the next time, you can do so by using flags with the pnpm local command. ```bash pnpm local [options] ``` List of available options: * `--service=` : Specifies which part of the application to develop. The values are `dashboard`, `api`, or `www` * `--skip-env`: Skips the environment setup prompt if specified. Example: ```bash pnpm local --service=dashboard --skip-env ``` # SDK development Source: https://unkey.com/docs/contributing/sdk-development Information for Unkey SDK developers # Telemetry Unkey collects anonymous telemetry data to help us understand usage of the framework. If you're authoring an SDK, you should record usage information and send it via `Upstash-Telemetry` headers. ### Typescript libraries The Unkey Typescript library `@unkey/api` is already set up to collect telemetry data. If you're writing a new SDK for a framework that makes use of that library under the hood, you just need to enable the user to disable telemetry; otherwise, pass it in the constructor. You can see an example of this via the Next.js SDK [here](https://github.com/unkeyed/unkey/blob/main/packages/nextjs/src/index.ts#L99). ### Telemetry request headers Unkey records telemetry data via three headers. You can see an example of how this is used in the Typescript SDK [here](https://github.com/unkeyed/unkey/blob/main/packages/api/src/client.ts#L138) Comma-separated list of strings recording SDKs. Can be multiple SDKs; for instance, the Next.js SDK will record both the Next.js SDK version and Typescript SDK version. Referring to the platform where the calling application is deployed. For example: `Vercel`, `Cloudflare`, `AWS`, `Deno` Referring to the programming runtime. For example: `edge-light`, `node@18`, `node@20.0.1` ```bash Sending Telemetry curl -XPOST 'https://api.unkey.dev/v1/keys.verifyKey' \ -H "Content-Type: application/json" \ -H "Unkey-Telemetry-SDK: @unkey/api@1.10.0" \ -H "Unkey-Telemetry-Platform: Vercel" \ -H "Unkey-Telemetry-Runtime: edge-light" \ -d '{ "key": "<...>" }' ``` # Architecture Source: https://unkey.com/docs/contributing/services/agent/architecture The agent is deployed as a cluster of machines to fly.io. Each machine is identical and capable of serving any incoming request. We run a gossip network between all machines for service discovery and failure detection. The gossip network will also be used for broadcasting configuration changes and cache invalidations. On top of the gossip layer, sits a consistent hash ring for sharding any kind of data across the cluster. More details about the architecture coming soon. # Cluster Source: https://unkey.com/docs/contributing/services/agent/cluster Running a cluster for high availablity and global distribution. One of our main goals has always been to offer the lowest latency possible to our users. The only option is to distribute the service across multiple machines in multiple regions. To make this easier, we are building the agent in a way that's infinitely horizontally scalable and deploy it behind a global load balancer. Each machine is identical and capable of serving any incoming request. It has access to the databases and will cache the data locally in memory or on disk. ## Why clustering? > If every machine can do everything, why do they need to communicate with each other? For some operations, such as ratelimiting, we require eventual consistency across the entire fleet. Machine A and machine B might receive ratelimit requests for the same identifier and if we do not coordinate the ratelimiting between them, we might end up exceeding the set limits by an unacceptable amount. ## Starting a cluster To start a cluster, you need to run the agent with a [cluster configuration](/contributing/services/agent/configuration). When starting, each node will try to join the cluster by contacting all of the other nodes. ## Membership We use [serf](https://www.serf.io/) for membership, failure detection and gossip communication. When a node joins the cluster, it will broadcast its presence to all other nodes and serf takes care of the rest. ## Consistent Hashing After membership has been established and each node in the cluster always knows about all other nodes, we can start sharding data across the cluster. We use [consistent hashing](https://en.wikipedia.org/wiki/Consistent_hashing) to shard data deterministically across all nodes in the cluster. # Configuration Source: https://unkey.com/docs/contributing/services/agent/configuration Configuration services and options for the agent service. The agent is configured via a JSON configuration file, which is loaded at startup using the `--config=` flag. Inside the config file, you may use `${ENV_NAME}` to reference environment variables. The agent will replace these references with the actual environment variable values at runtime. See example below. ## \$schema As the agent is in active development, the configuration spec might change frequently and this document could be outdated. The generated and up to date json schema can be found [on GitHub](https://github.com/unkeyed/unkey/blob/main/apps/agent/schema.json). ## Configuration Options A unique node id. This is used for identifying the node in the cluster. Generates a unique id if not provided. Enable pprof endpoints for profiling. Basic auth username for accessing the pprof endpoints. Basic auth password for accessing the pprof endpoints. Enable logging to an external sink. Enable axiom.co The dataset to log to. The axiom api token to use. Enable tracing to an external sink. Enable axiom.co The dataset to send traces to. The axiom api token to use. Enable sending metrics to an external sink. Enable axiom.co The dataset to send metrics to. The axiom api token to use. The region this agent is running in. Port to listen on. Send heartbeat to a URL. The url where heartbeat events are sent to. Interval in seconds to send heartbeats. The token to use for http authentication The bucket vault uses for storage. The url where the bucket is located. The access key id to use for s3. The access key secret to use for s3. The master keys to use for encryption, comma separated. Run and coordinate multiple agent nodes in a cluster. The token to use for http authentication. The host and port for serf to listen on. This node's internal address, including protocol and port. The strategy used for joining the cluster. Use one, not both. Addresses to join, comma separated. The AAAA record that returns a comma separated list, containing the ipv6 addresses of all nodes. ## Example Last updated on 2024-07-11 ```json { "$schema": "schema.json", "platform": "fly", "pprof": { "username": "${PPROF_USERNAME}", "password": "${PPROF_PASSWORD}" }, "image": "${FLY_IMAGE_REF}", "nodeId": "node_${FLY_MACHINE_ID}", "port": "8080", "region": "fly::${FLY_REGION}", "logging": { "axiom": { "dataset": "agent", "token": "${AXIOM_TOKEN}" } }, "tracing": { "axiom": { "dataset": "tracing", "token": "${AXIOM_TOKEN}" } }, "metrics": { "axiom": { "dataset": "metrics", "token": "${AXIOM_TOKEN}" } }, "services": { "ratelimit": { "authToken": "${AUTH_TOKEN}" }, "vault": { "s3Url": "${VAULT_S3_URL}", "s3Bucket": "${VAULT_S3_BUCKET}", "s3AccessKeyId": "${VAULT_S3_ACCESS_KEY_ID}", "s3AccessKeySecret": "${VAULT_S3_ACCESS_KEY_SECRET}", "masterKeys": "${VAULT_MASTER_KEYS}" } }, "cluster": { "authToken": "${AUTH_TOKEN}", "serfAddr": "[${FLY_PRIVATE_IP}]:${SERF_PORT}", "rpcAddr": "http://${FLY_PRIVATE_IP}:${RPC_PORT}", "join": { "dns": { "aaaa": "${FLY_APP_NAME}.internal" } } } } ``` # Profiling Source: https://unkey.com/docs/contributing/services/agent/profiling The agent exposes pprof endpoints for profiling. The following endpoints are available and require basic authentication to access them: * `/debug/pprof/` * `/debug/pprof/cmdline` * `/debug/pprof/profile` * `/debug/pprof/symbol` * `/debug/pprof/trace` To enable profiling, set the `pprof` configuration option in the agent configuration file. The agent will then expose the pprof endpoints protected by basic authentication. See [Configuration](/contributing/services/agent/configuration) for more information on how to configure the agent. ```json { "pprof": { "username": "PPROF_USERNAME", "password": "PPROF_PASSWORD" } } ``` There are some helper scripts available in the agent repository to interact with the pprof endpoints. The scripts are located in the [/apps/agent/scripts](https://github.com/unkeyed/unkey/tree/main/apps/agent/scripts) directory. These scripts are specific to our setup on fly.io and serve as an example. They should work for any setup with minor modifications. After running, your browser should open automatically and the pprof web interface allows you to analyze the profile data. ## Profiling the cpu ```bash cd apps/agent set PPROF_USERNAME=XXX set PPROF_PASSWORD=XXX set MACHINE_ID=XXX bash ./scripts/profile.bash ``` ## Profiling memory ```bash cd apps/agent set PPROF_USERNAME=XXX set PPROF_PASSWORD=XXX set MACHINE_ID=XXX bash ./scripts/heap.bash ``` # Testing Source: https://unkey.com/docs/contributing/testing James loves writing tests We use [vitest](https://vitest.dev/) for our unit and integration tests. You can run the tests with: ```bash pnpm install pnpm test ``` ## API Tests `/apps/api` is our core product and needs to be heavily tested. Unit tests are not enough so we also use integration tests: ### `integration` Full end to end tests require a running API either locally or in a deployed environment. ```bash cd apps/api UNKEY_BASE_URL= UNKEY_ROOT_KEY= pnpm test:integration ``` # Versioning Source: https://unkey.com/docs/contributing/versions How to release new versions of the repository. # Repository Version The main version of the repository is only for the `agent`. Sdks and other libraries have their own independent versioning. ## Releasing packages All of the npm packages are versioned via changesets. This allows us to have a dedicated version for the agent, while still allowing us to version each package independently. To release a new version of a package, you need to create a new changeset with your PR. This will trigger a GitHub action that will publish the new version of the package. In your feature branch, create a new changeset with `pnpm changeset` Commit the generated changeset alongside your changes. Changesets will be generated in the `.changeset` folder in the repository root. Create a new PR into `main`. *This step happens automatically in the CI* Once the PR is approved and merged, we create a new PR automatically in the CI, which consumes the changesets and bumps the versions accordingly. *This step happens automatically in the CI* Merging the version-bump pr will release all the packages to npm if necessary. ## Releasing a new agent version To release a new version of the agent, you need to create a new release on GitHub. This will trigger a GitHub action that will delpoy the new version. A prerelease version will only be deployed to our staging environment, while a release version will be deployed to production as well. # Vercel Source: https://unkey.com/docs/integrations/vercel Zero Config API Authenciation on Vercel ## Prerequisites * Created your [Unkey account](https://app.unkey.com/auth/sign-up) * Created an API in the [Unkey dashboard](https://app.unkey.com/apis) * [Vercel account](https://vercel.com/signup) ## Adding Vercel Integration Prefer a video? Checkout this video that walks through the steps below.