{"openapi":"3.0.1","servers":[{"url":"https://api.atlassian.com/forge/storage/kvs"}],"info":{"title":"Key-Value Store/Custom Entity Store REST API","description":"Forge provides hosted storage capabilities for storing your app's data:\n- **Key-Value Store** - stores data as key-value pairs\n- **Custom Entity Store** - stores data within custom data structures (entities)\nBoth capabilities have resources that can be used natively, or accessed by remote resources via REST API. For more information about both capabilities,\nsee [storage-api](https://developer.atlassian.com/platform/forge/runtime-reference/storage-api/).","version":"0.1.0","contact":{"email":"ecosystem-xen-dev@atlassian.com"}},"tags":[{"name":"Key-Value Store","description":"The Key-Value Store provides simple storage for key/value pairs.\nUse this to persistently store data that you'd like to retrieve through the\n[Query](#api-v1-query-post) operation.\n"},{"name":"Custom Entity Store","description":"The Custom Entity Store lets you store data in [custom entities](/platform/forge/runtime-reference/custom-entities/), which are data structures\nyou can define according to your app's needs. Custom entities let you assign multiple values\n(or \"attributes\") to a single key (or \"entity\") and define indexes to optimize queries against\nthese values.\n"}],"components":{"schemas":{"KeySchema":{"type":"object","required":["key"],"properties":{"key":{"type":"string"}}},"KeyValueSchema":{"type":"object","required":["key","value"],"properties":{"key":{"type":"string"},"value":{"$ref":"#/components/schemas/ValueSchema"}}},"ValueSchema":{"oneOf":[{"type":"string"},{"type":"boolean"},{"type":"number"},{"type":"array","items":{}},{"type":"object"}]},"QueryRequestSchema":{"type":"object","properties":{"limit":{"type":"number"},"after":{"type":"string"},"where":{"type":"array","items":{"$ref":"#/components/schemas/WhereCondition"}}}},"WhereCondition":{"type":"object","properties":{"condition":{"type":"string","enum":["BEGINS_WITH"]},"property":{"type":"string","enum":["key"]},"values":{"type":"array","items":{"$ref":"#/components/schemas/ValueSchema"}}},"required":["condition","property","values"]},"QueryResponseSchema":{"type":"object","required":["data"],"properties":{"cursor":{"type":"string"},"data":{"type":"array","items":{"$ref":"#/components/schemas/QueryResponseItemSchema"}}}},"QueryResponseItemSchema":{"type":"object","required":["key","value"],"properties":{"key":{"type":"string"},"value":{"$ref":"#/components/schemas/ValueSchema"}}},"EntityKeySchema":{"type":"object","required":["key","entityName"],"properties":{"key":{"type":"string"},"entityName":{"type":"string"}}},"EntityKeyValueSchema":{"type":"object","required":["key","value","entityName"],"properties":{"key":{"type":"string"},"value":{"type":"object","additionalProperties":true},"entityName":{"type":"string"}}},"EntityQueryRequestSchema":{"type":"object","properties":{"entityName":{"type":"string"},"indexName":{"type":"string"},"partition":{"type":"array","items":{"$ref":"#/components/schemas/PartitionSchema"}},"range":{"type":"object","properties":{"condition":{"type":"string","enum":["BEGINS_WITH","BETWEEN","EQUAL_TO","GREATER_THAN","GREATER_THAN_EQUAL_TO","LESS_THAN","LESS_THAN_EQUAL_TO"]},"values":{"type":"array","items":{"$ref":"#/components/schemas/ValueSchema"}}},"required":["condition","values"]},"filters":{"$ref":"#/components/schemas/FilterSchema"},"sort":{"type":"string","enum":["ASC","DESC"]},"cursor":{"type":"string"},"limit":{"type":"integer","format":"int32"}},"required":["entityName","indexName"]},"PartitionSchema":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"}]},"FilterSchema":{"type":"object","oneOf":[{"$ref":"#/components/schemas/AndFilterSchema"},{"$ref":"#/components/schemas/OrFilterSchema"}]},"AndFilterSchema":{"type":"object","required":["and"],"properties":{"and":{"type":"array","items":{"$ref":"#/components/schemas/FilterCondition"}}},"additionalProperties":false},"FilterCondition":{"type":"object","properties":{"condition":{"type":"string","enum":["BEGINS_WITH","BETWEEN","CONTAINS","EQUAL_TO","EXISTS","GREATER_THAN","GREATER_THAN_EQUAL_TO","LESS_THAN","LESS_THAN_EQUAL_TO","NOT_CONTAINS","NOT_EQUAL_TO","NOT_EXISTS"]},"property":{"type":"string"},"values":{"type":"array","items":{"$ref":"#/components/schemas/ValueSchema"}}},"required":["condition","property","values"]},"OrFilterSchema":{"type":"object","required":["or"],"properties":{"or":{"type":"array","items":{"$ref":"#/components/schemas/FilterCondition"}}},"additionalProperties":false}}},"paths":{"/v1/get":{"post":{"tags":["Key-Value Store","Untyped","Public"],"summary":"Get value by key","description":"Gets a value by key.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeySchema"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeyValueSchema"}}},"description":"Successfully retrieved the value corresponding to the key"},"400":{"description":"Possible error codes:\n- ```KEY_TOO_SHORT``` - The provided key needs to be more than one character.\n- ```KEY_TOO_LONG``` - The provided key has exceeded the maximum 500 characters.\n- ```INVALID_KEY``` - The provided key does not match the regex: ```/^(?!\\s+$)[a-zA-Z0-9:._\\s-#]+$/```.\n\n See [Error handling](/platform/forge/remote/accessing-storage/#error-handling) for more information about each error code."},"404":{"description":"Possible error codes:\n- ```KEY_NOT_FOUND``` - The provided key does not exist."}}}},"/v1/set":{"post":{"tags":["Key-Value Store","Untyped","Public"],"description":"Stores a JSON value with a specified key. Forge resolves write conflicts using a last-write-wins strategy.","summary":"Set value by key","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeyValueSchema"}}}},"responses":{"204":{"description":"Successfully set the value to the corresponding key"},"400":{"description":"Possible error codes:\n- ```KEY_TOO_SHORT``` - The provided key needs to be more than one character.\n- ```KEY_TOO_LONG``` - The provided key has exceeded the maximum 500 characters.\n- ```INVALID_KEY``` - The provided key does not match the regex: ```/^(?!\\s+$)[a-zA-Z0-9:._\\s-#]+$```.\n- ```MAX_SIZE``` - The provided value has exceeded the maximum size limit.\n- ```MAX_DEPTH``` - The provided value has exceeded the maximum object depth (32) limit.\n\nSee [Error handling](/platform/forge/remote/accessing-storage/#error-handling) for more information about each error code."}}}},"/v1/delete":{"post":{"tags":["Key-Value Store","Untyped","Public"],"description":"Deletes a value by key. Write conflicts are resolved using a last-write-wins strategy.","summary":"Delete value by key","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeySchema"}}}},"responses":{"204":{"description":"Successfully deleted the key and the corresponding value"},"400":{"description":"Possible error codes:\n- ```KEY_TOO_SHORT``` - The provided key needs to be more than one character.\n- ```KEY_TOO_LONG``` - The provided key has exceeded the maximum 500 characters.\n- ```INVALID_KEY``` - The provided key does not match the regex: ```/^(?!\\s+$)[a-zA-Z0-9:._\\s-#]+$```.\n\n See [Error handling](/platform/forge/remote/accessing-storage/#error-handling) for more information about each error code."},"404":{"description":"Possible error codes:\n- ```KEY_NOT_FOUND``` - The provided key does not exist."}}}},"/v1/query":{"post":{"tags":["Key-Value Store","Untyped","Public"],"description":"Retrieve key-value pairs matching the provided list of criteria. This method does not return secret values set by [Set secret value](/platform/forge/rest/api-group-key-value-store/#api-v1-secret-set-post).","summary":"Query key-value pairs","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryRequestSchema"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","$ref":"#/components/schemas/QueryResponseSchema"}}},"description":"Successfully retrieved the data from storage"},"400":{"description":"Possible error codes:\n- ```INVALID_FILTER_CONDITION``` - The specified condition is not supported for filters.\n- ```INVALID_FILTER_VALUES``` - The specified number of values is not supported by the condition.\n- ```INVALID_KEY``` - The provided key does not match the regex: ```/^(?!\\s+$)[a-zA-Z0-9:._\\s-#]+$```.\n- ```KEY_TOO_LONG``` - The provided key has exceeded the maximum 500 characters.\n- ```KEY_TOO_SHORT``` - The provided key needs to be more than one character.\n- ```LIST_QUERY_LIMIT_EXCEEDED``` - Limit for list query should be below 100.\n- ```QUERY_WHERE_FIELD_INVALID``` - The specified field is not supported for filters.\n- ```QUERY_WHERE_INVALID``` - Queries should contain only a single \"where\" clause.\n\n   See [Error handling](/platform/forge/remote/accessing-storage/#error-handling) for more information about each error code."}}}},"/v1/secret/get":{"post":{"tags":["Key-Value Store","Secret","Public"],"description":"Gets a value by key, which was stored using [Set secret value by key](/platform/forge/rest/api-group-key-value-store/#api-v1-secret-set-post). The value is decrypted before being returned.","summary":"Get secret value by key","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeySchema"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeyValueSchema"}}},"description":"Successfully retrieved the decrypted value corresponding to the key"},"400":{"description":"Possible error codes:\n- ```KEY_TOO_SHORT``` - The provided key needs to be more than one character.\n- ```KEY_TOO_LONG``` - The provided key has exceeded the maximum 500 characters.\n- ```INVALID_KEY``` - The provided key does not match the regex: ```/^(?!\\s+$)[a-zA-Z0-9:._\\s-#]+$/```.\n\n See [Error handling](/platform/forge/remote/accessing-storage/#error-handling) for more information about each error code."},"404":{"description":"Possible error codes:\n- ```KEY_NOT_FOUND``` - The provided key does not exist."}}}},"/v1/secret/set":{"post":{"tags":["Key-Value Store","Secret","Public"],"description":"Store sensitive credentials in JSON format, with encryption. Values set with this method can only be accessed with [Get secret value by key](/platform/forge/rest/api-group-key-value-store/#api-v1-secret-get-post). Write conflicts are resolved using a last-write-wins strategy.","summary":"Set secret value by key","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeyValueSchema"}}}},"responses":{"204":{"description":"Successfully set the value to the corresponding key with encryption"},"400":{"description":"Possible error codes:\n- ```KEY_TOO_SHORT``` - The provided key needs to be more than one character.\n- ```KEY_TOO_LONG``` - The provided key has exceeded the maximum 500 characters.\n- ```INVALID_KEY``` - The provided key does not match the regex: ```/^(?!\\s+$)[a-zA-Z0-9:._\\s-#]+$```.\n- ```MAX_SIZE``` - The provided value has exceeded the maximum size limit.\n\n See [Error handling](/platform/forge/remote/accessing-storage/#error-handling) for more information about each error code."}}}},"/v1/secret/delete":{"post":{"tags":["Key-Value Store","Secret","Public"],"description":"Deletes a secret value by key.","summary":"Delete secret value by key","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeySchema"}}}},"responses":{"204":{"description":"Successfully deleted the key and the corresponding encrypted value"},"400":{"description":"Possible error codes:\n- ```KEY_TOO_SHORT``` - The provided key needs to be more than one character.\n- ```KEY_TOO_LONG``` - The provided key has exceeded the maximum 500 characters.\n- ```INVALID_KEY``` - The provided key does not match the regex: ```/^(?!\\s+$)[a-zA-Z0-9:._\\s-#]+$```.\n\n See [Error handling](/platform/forge/remote/accessing-storage/#error-handling) for more information about each error code."},"404":{"description":"Possible error codes:\n- ```KEY_NOT_FOUND``` - The provided key does not exist."}}}},"/v1/entity/get":{"post":{"tags":["Custom Entity Store","Entity","Public"],"description":"Gets a custom entity value by key.","summary":"Get custom entity value by key","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntityKeySchema"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntityKeyValueSchema"}}},"description":"Successfully retrieved the value corresponding to the key and the entity"},"400":{"description":"Possible error codes:\n- ```EMPTY_KEY``` - Key cannot be empty.\n- ```ENTITY_TYPE_TOO_SHORT``` - The provided key needs to be more than 3 characters.\n- ```ENTITY_TYPE_TOO_LARGE``` - The provided key has exceeded the maximum 60 characters.\n- ```INVALID_ENTITY_TYPE``` - The provided key does not match the regex: ```/^(?![\\.\\-])(?!.*\\.{2})[a-z0-9:\\-.]*(?<![.])$/```\n- ```INVALID_KEY``` - The provided key does not match the regex: ```/^(?!\\s+$)[a-zA-Z0-9:._\\s-#]+$/```\n- ```KEY_TOO_LONG``` - The provided key has exceeded the maximum 500 characters.\n\n See [Error handling](/platform/forge/remote/accessing-storage/#error-handling) for more information about each error code."},"404":{"description":"Possible error codes:\n- ```KEY_NOT_FOUND``` - The provided key does not exist."}}}},"/v1/entity/set":{"post":{"tags":["Custom Entity Store","Entity","Public"],"description":"Stores a JSON value with a specified key, for the selected entity.","summary":"Set custom entity value by key","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntityKeyValueSchema"}}}},"responses":{"204":{"description":"Successfully set the value to the corresponding key and the entity"},"400":{"description":"Possible error codes:\n- ```EMPTY_KEY``` - Key cannot be empty.\n- ```ENTITY_TYPE_TOO_SHORT``` - The provided key needs to be more than 3 characters.\n- ```ENTITY_TYPE_TOO_LARGE``` - The provided key has exceeded the maximum 60 characters.\n- ```INVALID_ENTITY_TYPE``` - The provided key does not match the regex: ```/^(?![\\.\\-])(?!.*\\.{2})[a-z0-9:\\-.]*(?<![.])$/```\n- ```INVALID_ENTITY_VALUE``` - Entity values must match one of the types defined in [custom-entities](https://developer.atlassian.com/platform/forge/runtime-reference/custom-entities/#values).\n- ```INVALID_ENTITY_ATTRIBUTE``` - The specified attribute name is a reserved value and cannot be utilized.\n- ```INVALID_KEY``` - The provided key does not match the regex: ```/^(?!\\s+$)[a-zA-Z0-9:._\\s-#]+$/```\n- ```KEY_TOO_LONG``` - The provided key has exceeded the maximum 500 characters.\n- ```MAX_SIZE``` - The provided attribute value has exceeded the maximum size limit.\n- ```MAX_DEPTH``` - The provided attribute value has exceeded the maximum object depth (32) limit.\n\n See [Error handling](/platform/forge/remote/accessing-storage/#error-handling) for more information about each error code."}}}},"/v1/entity/delete":{"post":{"tags":["Custom Entity Store","Entity","Public"],"description":"Deletes a value by key, for the selected entity.","summary":"Delete custom entity value by key","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntityKeySchema"}}}},"responses":{"204":{"description":"Successfully deleted the key and the corresponding value of the entity"},"400":{"description":"Possible error codes:\n- ```EMPTY_KEY``` - Key cannot be empty.\n- ```ENTITY_TYPE_TOO_SHORT``` - The provided key needs to be more than 3 characters.\n- ```ENTITY_TYPE_TOO_LARGE``` - The provided key has exceeded the maximum 60 characters.\n- ```INVALID_ENTITY_TYPE``` - The provided key does not match the regex: ```/^(?![\\.\\-])(?!.*\\.{2})[a-z0-9:\\-.]*(?<![.])$/```\n- ```INVALID_KEY``` - The provided key does not match the regex: ```/^(?!\\s+$)[a-zA-Z0-9:._\\s-#]+$/```\n- ```KEY_TOO_LONG``` - The provided key has exceeded the maximum 500 characters.\n\n See [Error handling](/platform/forge/remote/accessing-storage/#error-handling) for more information about each error code."},"404":{"description":"Possible error codes:\n- ```KEY_NOT_FOUND``` - The provided key does not exist."}}}},"/v1/entity/query":{"post":{"tags":["Custom Entity Store","Entity","Public"],"description":"Retrieves custom entities matching the provided list of criteria using query conditions. See [Querying the Custom Entity Store](https://developer.atlassian.com/platform/forge/runtime-reference/storage-api-query-complex/) for more information about building complex queries.","summary":"Query custom entities","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntityQueryRequestSchema"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"type":"object","$ref":"#/components/schemas/QueryResponseSchema"}}},"description":"Successfully retrieved the data from storage for an entity"},"400":{"description":"Possible error codes:\n- ```INVALID_ENTITY_INDEX``` - The custom entity index provided is invalid. The index name is a reserved value and cannot be utilized.\n- ```COMPLEX_QUERY_PAGE_LIMIT_NOT_IN_RANGE``` - The page limit must be set between 1 and 100.\n- ```INVALID_FILTER_OPERATORS_COMBINATION``` - Filter operators \"and\" and \"or\" cannot be present at the same level.\n- ```EMPTY_FILTER_OPERATOR``` - Filter operators \"and\" and \"or\" cannot be empty.\n- ```INSUFFICIENT_FILTER_VALUES``` - The specified condition needs at least two values.\n\n See [Error handling](/platform/forge/remote/accessing-storage/#error-handling) for more information about each error code."}}}}},"x-atlassian-narrative":{"documents":[{"title":"About","anchor":"about","body":"Forge provides hosted storage capabilities that let you store data in your app installation. The following hosted storage capabilities can be accessed by your remote via REST API calls:\n\n- **Key-value store**: lets you store data in key-value pairs.\n\n- **Custom Entity Store** : lets you store data based on custom data structures specific to your app’s needs and query patterns.\n\nFor detailed information about prerequisites, request shape, and error handling, see [Accessing Forge storage via REST API](/platform/forge/remote/accessing-storage).\n\nEach installation of your app is subject to the API’s quotas and limits. See [Storage quotas](https://developer.atlassian.com/platform/forge/platform-quotas-and-limits/#storage-quotas) and [Storage limits](https://developer.atlassian.com/platform/forge/platform-quotas-and-limits/#storage-limits) for more details."},{"title":"Authentication and authorization","anchor":"auth","body":"Requests to this API are processed by an authentication service that\nonly accepts `OAuth` bearer tokens as authentication. \n\nThis service will return either of the following statuses in case of an\nerror:\n\n- `401: Unauthorized`: either your request provided an invalid or expired token, or was missing an `Authorization` header.\n\n- `403 Forbidden`: your request used an invalid route. Either the route doesn't exist, or it points to a resource that can't be accessed by non-Atlassian services.\n\nYour app must supply the `OAuth` token in the `Authorization: Bearer\n{bearerToken}` header of the request."},{"title":"Quotas and limits","anchor":"quotas","body":"Forge hosted storage capabilities are subject to limits, usage, and syntax constraints. \nThese include limits to the number of operations, key lengths, and object depth. \nAny request that exceeds a quota or limit will return a `429` status with an error code of `RATE_LIMIT_EXCEEDED`.\n  \nSee [Storage quotas](/platform/forge/platform-quotas-and-limits/#storage-quotas) and\n[Storage limits](/platform/forge/platform-quotas-and-limits/#storage-limits) \nfor details about relevant constraints."}]}}