Skip to main content

InCountry REST API documentation

Table of сontents

Welcome to InCountry REST API reference documentation. You can use this REST API to build apps for taking advantage of data residency services provided by InCountry. This page documents the REST resources provided by the InCountry Data Residency-as-a-Service (DRaaS), along with the expected HTTP response codes and sample requests.

Overview

InCountry REST API is a set of RESTful methods that allow you to query regulated data from the InCountry Data Residency-as-a-Service (DRaaS). It simplifies data communication and lets you quickly build applications with data localization capabilities.

The data flow diagram is shown below:

REST API Diagram

Authentication and authorization

InCountry REST API uses OAuth2 to authenticate and authorize requests with access tokens that are issued by the authentication server. To get a token, you need to create a REST API integration on the InCountry Portal and use the generated Client ID and Client Secret to get an access token for authorizing your data communication requests.

InCountry REST API supports two ways of working with requests:

  1. requests coming from the application backend

  2. requests coming from the application frontend

Depending on the source of the request, you need to properly implement the authorization flow within your application for communicating regulated data between your application and InCountry REST API.

Requesting a token

note

This procedure is common for requests coming from the application backend and frontend. The only difference for frontend requests is that you need to specify only the address of the REST API instance and exclude the address of the PoP API instance.

POST https://{oauth_endpoint}/oauth2/token

Instead of the {oauth_endpoint} part, enter the address of the OAuth server depending on the region where the country is located.

  • EMEA: https://auth-emea.incountry.com/

  • APAC: https://auth-apac.incountry.com/

note

EMEA unites countries located in Europe, the Middle East, and Africa.

APAC unites countries located in the region around the Western Pacific Ocean.

TO FIND OUT THE APPROPRIATE OAUTH SERVER FOR YOUR COUNTRY, PLEASE CHECK THIS PAGE.

As authorization credentials, you need to pass the Client ID (as username) and Client Secret (as password) that you received on the InCountry Portal. The authorization type should be basic authorization. It will transform authorization credentials into Base64 format.

Within the request body, you need to pass additional keys:

KeyValueDescription
grant_typeclient_credentials
audienceFor example:
https://se-restapi-mt-01.api.incountry.io https://se-mt-01.incountry.api.incountry.io
You need to pass the address of the REST API server. It will be provided by the InCountry Portal when you create an integration of the restapi type. Such address looks like:
https://{country_code}-restapi-mt-01.api.incountry.io
Besides, the address of a REST API server you need to pass the address of the PoP API instance within the same country where a REST API server is located. Such address looks like:
https://{country_code}-mt-01.api.incountry.io
Warning For requests coming from the application frontend, you do not need to pass the PoP API address, only the REST API address.
scopeFor example:
f2e5a966-1564-4c25-a3bf-0ef7a231fb2b
Identifier of the environment within the target country. The environment ID should correspond to the authorization credentials (Client ID and Client Secret).
cURL request

curl --location --request POST
--url 'https://{oauth_endpoint}/oauth2/token' \
--header 'Authorization: Basic base64{your_client_id:your_client_secret}' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode 'audience={rest_api_address popapi_address)' \
--data-urlencode 'scope={your_environment_id}'

note

For the audience parameter, please use the appropriate endpoint that you receive upon the creation of the REST API service.

note

For the Authorization part, you need to encode the {client_id:client_secret} string into a base64 string. For example, after appending Client Secret to Client ID, you should get something like this:

2681cad2-61a2-467f-a82c-a974e6d891e9:SGmdEj6plYd5nSeY-b-NHmCX3f

After base64 encoding this string, will look like this:

MjY4MWNhZDItNjFhMi00NjdmLWE4MmMtYTk3NGU2ZDg5MWU5OlNHbWRFajZwbFlkNW5TZVktYi1OSG1DWDNm

For testing purposes on non-production data, you can use the following service for base64 encoding.

As a response from the OAuth server, you will receive the following:

  • access_token - token string.

  • expires_in - life span of a generated token in seconds before it expires.

  • scope - environment ID.

  • token_type - bearer.

Once you have received the access token, use it for data management requests that you perform.

note

The access token is valid for 300 seconds, then it expires. You need further to get a new token by following the same approach.

Request authorization for frontend calls

InCountry REST API provides an additional authorization flow that you can use to query and manage regulated records from the application frontend.

note

See the Frontend-initiated requests for the list of the REST API endpoints supporting this authorization mechanism.

Prerequisites

For correct operation of the authorization flow of frontend calls, you need to implement an additional endpoint on the application backend. This endpoint must check ACL (access-control lists) and filter out records which a current user (requesting regulated data) is not allowed to view.

For example, you implement an endpoint:

POST /api/user/check

It should take the following headers:

Authorizaation: Bearer {clients oauth token}

It should take the response body having the following structure:

{
"operation": "read", // find, create, update, attachFile, delete, etc.
"params": { // depends on operation. E.g. find
"ids": ["id1", "id2"],
"fields": ["name", "email"], // which fields from the body are accessible,
"keys": ["key1", "key2", "range_key1"] // which keys to return from record
}
}

Authorization flow for frontend calls

Authorization flow for frontend calls

How the flow works:

  1. The application frontend obtains an OAuth token (from InCountry) and a client authorization token.

  2. The application frontend performs a find request with the obtained tokens to the REST API.

  3. The REST API retrieves records matching the provided filter and extracts their identifiers.

  4. The REST API performs a request to the application backend and provides record identifiers, client authorization token, and the field list.

  5. The application backend returns the list of filtered record identifiers and the field list which the current user can view.

  6. The REST API returns the list of filtered records (applying the row-level and filed-level access-control lists) to the application frontend for rendering.

Data Encryption

InCountry REST API is using the AES-GCM encryption with a 256-bit AES key and a 96-bit nonce.

URI structure

InCountry REST API provides access to resources (like data entities) via URI paths. To use REST API, your application makes an HTTP request and parses the response.

InCountry REST API uses JSON as its communication format and the standard HTTP methods like POST, GET, and DELETE. URIs for InCountry REST API resources have the following structure:

//For record management (backend):
https://{host}/api/records/{resource_name}

//For attachment management(backend):
https://{host}/api/records/{country}/{record_key}/files/{file_id}

//For record and attachment managemnt (frontend):
https://{host}/webapi/records/{resource_name}
https://{host}/api/records//{record_key}/files/{resorce_name}

Getting started with REST API

To get started with the REST API, you can download the Postman collection of requests. You can use this collection to perform test requests and queries to the InCountry DRaaS.

  1. Create a new REST integration on the InCountry Portal.

  2. Download the Postman collection and import it into the application.

  3. Add your Client ID and Client Secret into the token acquiring request.

  4. Perform data communication requests with regulated data.

Download RestAPI Demo oAuth Postman Collection

REST API resources

Below you can find the available API resources within InCountry REST API.

Management of records

You can manage records on the InCountry DRaaS, as follows:

Available record fields

All records saved to the InCountry Vault may have the following fields:

FieldTypeStorageSpecifics
record_keystringHashedThis is a unique identifier of the record which is returned by the REST API. This field is used to store the primary key of the record. This field is used as an alias for the deprecated key field.
bodystringEncryptedYou can also stringify data in the JSON format and save it within this field.
precommit_bodystringEncryptedYou can use this field to store some service information about the record.
profile_keystringHashedThe unique identifier of the data record in an external system. It can be used for storing any other data string if needed.
parent_keystringHashedKey of the parent record which the current record is attributed to.
range_keyNintegerPlainN can be between 1 … 10. You can use up to 10 fields.The range_keyN fields are used for value range filtration of numerical values.
service_keyNstringHashedN can take from 1 to 5. You can have up to 5 fields.The service_keyN fields can be used for storing additional text information.
keyNstringHashed / PlainN can take from 1 to 20. You can use up to 20 fields.This value can be hashed or remain as a plain value depending on your configuration. This field can be used for record lookup.
created_atstring(date-time)PlainThe timestamp in the ISO-8601 format when a record was created.
updated_atstring(date-time)PlainThe timestamp in the ISO-8601 format when a record was updated.
expires_atstring(date-time)PlainThis field determines the date and time when the record will be automatically deleted from the InCountry Vault.
countryISO country code (lowercase)PlainCountry where a new record is stored.
attachmentsobjectFor the details on the attachments field, please see the Management of attachments section.

Creating a single record

POST /api/records

note

Alternatively, this request can be used to update the record. Be careful, as it rewrites the data record with new values you provide.

ParameterTypeValueDescription
useAliasesquery?useAliases=trueAppend this string to the request address to use key-alias mappings instead of actual record’s keys.
Warning Don’t append anything to use the actual record’s keys.

Request body

Please see the example of the request body structure.

Example

{
"key": "string",
"record_key": "string",
"body": "string / string in the JSON format",
"precommit_body": "string",
"profile_key": "string",
"parent_key": "string",
"range_key": 0,
"range_key1": 0,
"range_key2": 0,
"range_key3": 0,
"range_key4": 0,
"range_key5": 0,
"range_key6": 0,
"range_key7": 0,
"range_key8": 0,
"range_key9": 0,
"range_key10": 0,
"service_key1": "string",
"service_key2": "string",
"service_key3": "string",
"service_key4": "string",
"service_key5": "string",
"key1": "string",
"key2": "string",
"key3": "string",
"key4": "string",
"key5": "string",
"key6": "string",
"key7": "string",
"key8": "string",
"key9": "string",
"key10": "string",
"key11": "string",
"key12": "string",
"key13": "string",
"key14": "string",
"key15": "string",
"key16": "string",
"key17": "string",
"key18": "string",
"key19": "string",
"key20": "string",
"expires_at": "2021-04-07T07:15:44.393Z",
"country": "string"
}

note

The country code is defined by the Rest API instance. For one instance, you can use only one country code. For example, for https://se-restapi-mt-01.incountry.io it can only be se.

cURL request

curl --request POST \
--url 'https://{restApiURLAddress}/api/records' \
--header 'Authorization: Bearer {ACCESS_TOKEN}' \
--header 'Content-Type: application/json' \
--data '{
"record_key": "d1c2e12cfeababc8b95daf6902e210b1",
"profile_key": "4274e510a2f41aeb9e8e0f8b56ff6c2",
"range_key": 2000,
"key10": "New",
"key9": null,
"key8": null,
"key7": null,
"key6": null,
"key5": null,
"key4": "Shipping",
"key3": null,
"key2": null,
"key1": "Additional info",
"key": null,
"body": "{\"name\":\"John\",\"vehicle\":\"Audi\"}",
"country": "se"
}'

Responses

STATUS 201 - application/json A record has been created successfully. Returns a record key and record details similar to the data you submitted within the request.

Example

{
"country": "se",
"key": "d1c2e12cfeababc8b95daf6902e210b1",
"record_key": "d1c2e12cfeababc8b95daf6902e210b1",
"profile_key": "4274e510a2f41aeb9e8e0f8b56ff6c2",
"range_key": 2000,
"range_key1": 2000,
"body": "{\"name\":\"John\",\"vehicle\":\"Audi\"}",
"key1": "Additional info",
"key2": null,
"key3": null,
"key4": "Shipping",
"key5": null,
"key6": null,
"key7": null,
"key8": null,
"key9": null,
"key10": "New"
}

STATUS 400 - application/json An invalid record has been provided.

STATUS 401 - Access is denied.

STATUS 409 - InCountry Vault for the country is not available.

STATUS 415 - An unsupported request content type.

STATUS 422 - Validation of input parameters has failed.

STATUS 429 - The number of allowed requests has been exceeded.

STATUS 5** - Server error.

Creating multiple records

POST /api/records/batch

ParameterTypeValueDescription
useAliasesquery?useAliases=trueAppend this string to the request address to use key-alias mappings instead of actual record’s keys.
Warning Don’t append anything to use the actual record’s keys.

Request body

Please see the example of the request structure.

Example

{
"country": "string",
"records": [
{
"key": "string",
"record_key": "string",
"body": "string / string in the JSON format",
"precommit_body": "string",
"profile_key": "string",
"parent_key": "string",
"range_key": 0,
"range_key1": 0,
"range_key2": 0,
"range_key3": 0,
"range_key4": 0,
"range_key5": 0,
"range_key6": 0,
"range_key7": 0,
"range_key8": 0,
"range_key9": 0,
"range_key10": 0,
"service_key1": "string",
"service_key2": "string",
"service_key3": "string",
"service_key4": "string",
"service_key5": "string",
"key1": "string",
"key2": "string",
"key3": "string",
"key4": "string",
"key5": "string",
"key6": "string",
"key7": "string",
"key8": "string",
"key9": "string",
"key10": "string",
"key11": "string",
"key12": "string",
"key13": "string",
"key14": "string",
"key15": "string",
"key16": "string",
"key17": "string",
"key18": "string",
"key19": "string",
"key20": "string",
"expires_at": "2021-04-07T07:15:44.435Z"
},
{
"key": "string",
"record_key": "string",
"body": "string / string in the JSON format",
"precommit_body": "string",
"profile_key": "string",
"parent_key": "string",
"range_key": 0,
"range_key1": 0,
"range_key2": 0,
"range_key3": 0,
"range_key4": 0,
"range_key5": 0,
"range_key6": 0,
"range_key7": 0,
"range_key8": 0,
"range_key9": 0,
"range_key10": 0,
"service_key1": "string",
"service_key2": "string",
"service_key3": "string",
"service_key4": "string",
"service_key5": "string",
"key1": "string",
"key2": "string",
"key3": "string",
"key4": "string",
"key5": "string",
"key6": "string",
"key7": "string",
"key8": "string",
"key9": "string",
"key10": "string",
"key11": "string",
"key12": "string",
"key13": "string",
"key14": "string",
"key15": "string",
"key16": "string",
"key17": "string",
"key18": "string",
"key19": "string",
"key20": "string",
"expires_at": "2021-04-07T07:15:44.435Z"
}
]
}

cURL request

curl --request POST \
--url 'https://{restApiURLAddress}/api/records/batch' \
--header 'Authorization: Bearer {ACCESS_TOKEN}' \
--header 'Content-Type: application/json' \
--data '{
"records": [
{
"record_key": "d1c2e12cfeababc8b95daf6902e210b1",
"profile_key": "4274e510a2f41aeb9e8e0f8b56ff6c2",
"range_key": 2000,
"key10": "New",
"key9": null,
"key8": null,
"key7": null,
"key6": null,
"key5": null,
"key4": "Shipping",
"key3": null,
"key2": null,
"key1": "Additional info",
"key": null,
"body": "{\"name\":\"John\",\"vehicle\":\"Audi\"}"
},
{
"record_key": "69f6a71405facac91d002dc9adce85fa",
"profile_key": "baab015f2f9c350ab610fddd3986c53",
"range_key": 3000,
"key10": "New",
"key9": null,
"key8": null,
"key7": null,
"key6": null,
"key5": null,
"key4": "Shipping",
"key3": null,
"key2": null,
"key1": "Additional info",
"key": null,
"body": "{\"name\":\"Alice\",\"vehicle\":\"Mercedes\"}"
}
],
"country": "se"
}'

Responses

STATUS 201 - application/json Records have been created successfully. Returns record keys and record details similar to data you submitting within the request payload.

Example

[
{
"country": "se",
"key": "d1c2e12cfeababc8b95daf6902e210b1",
"record_key": "d1c2e12cfeababc8b95daf6902e210b1",
"profile_key": "4274e510a2f41aeb9e8e0f8b56ff6c2",
"range_key": 2000,
"range_key1": 2000,
"body": "{\"name\":\"John\",\"vehicle\":\"Audi\"}",
"key1": "Additional info",
"key2": null,
"key3": null,
"key4": "Shipping",
"key5": null,
"key6": null,
"key7": null,
"key8": null,
"key9": null,
"key10": "New"
},
{
"country": "se",
"key": "69f6a71405facac91d002dc9adce85fa",
"record_key": "69f6a71405facac91d002dc9adce85fa",
"profile_key": "baab015f2f9c350ab610fddd3986c53",
"range_key": 3000,
"range_key1": 3000,
"body": "{\"name\":\"Alice\",\"vehicle\":\"Mercedes\"}",
"key1": "Additional info",
"key2": null,
"key3": null,
"key4": "Shipping",
"key5": null,
"key6": null,
"key7": null,
"key8": null,
"key9": null,
"key10": "New"
}
]

STATUS 400 - application/json Invalid records have been provided.

STATUS 401 - Access is denied.

STATUS 409 - InCountry Vault for the country is not available.

STATUS 415 - An unsupported request content type.

STATUS 422 - A record cannot be processed.

STATUS 429 - The number of allowed requests has been exceeded.

STATUS 5** - Server error.

Duplicating a single record

POST /api/records/clone

This request can duplicate a record as-is or modify the duplicated record on the fly.

ParameterTypeValueDescription
useAliasesquery?useAliases=trueAppend this string to the request address to use key-alias mappings instead of actual record’s keys.
Warning Don’t append anything to use the actual record’s keys.

Request body

Please see the example of the request body structure. It contains the section which specifies filters to find the records for duplication and the section to specify the values for a record update.

Example

{
"filter": {
"record_key": "string",
"profile_key": "string",
"parent_key": "string",
"range_key1": 0,
"range_key2": 0,
"range_key3": 0,
"range_key4": 0,
"range_key5": 0,
"decimal_key1": 0,
"decimal_key2": 0,
"decimal_key3": 0,
"decimal_key4": 0,
"decimal_key5": 0,
"key1": "string",
"key2": "string",
"key3": "string",
"key4": "string",
"key5": "string",
"key6": "string",
"key7": "string",
"key8": "string",
"key9": "string",
"key10": "string",
"key11": "string",
"key12": "string",
"key13": "string",
"key14": "string",
"key15": "string",
"key16": "string",
"key17": "string",
"key18": "string",
"key19": "string",
"key20": "string",
"key21": "string",
"key22": "string",
"key23": "string",
"key24": "string",
"key25": "string",
"service_key1": "string",
"service_key2": "string",
"service_key3": "string",
"service_key4": "string",
"service_key5": "string",
"version": 0,
"search_keys": "string",
"created_at": "2023-08-07T07:45:38.256Z",
"updated_at": "2023-08-07T07:45:38.256Z"
},
"update_with": {
"record_key": "string",
"body": "string",
"profile_key": "string",
"parent_key": "string",
"range_key1": 0,
"range_key2": 0,
"range_key3": 0,
"range_key4": 0,
"range_key5": 0,
"range_key6": 0,
"range_key7": 0,
"range_key8": 0,
"range_key9": 0,
"range_key10": 0,
"service_key1": "string",
"service_key2": "string",
"service_key3": "string",
"service_key4": "string",
"service_key5": "string",
"key1": "string",
"key2": "string",
"key3": "string",
"key4": "string",
"key5": "string",
"key6": "string",
"key7": "string",
"key8": "string",
"key9": "string",
"key10": "string",
"key11": "string",
"key12": "string",
"key13": "string",
"key14": "string",
"key15": "string",
"key16": "string",
"key17": "string",
"key18": "string",
"key19": "string",
"key20": "string",
"key21": "string",
"key22": "string",
"key23": "string",
"key24": "string",
"key25": "string",
"decimal_key1": 0,
"decimal_key2": 0,
"decimal_key3": 0,
"decimal_key4": 0,
"decimal_key5": 0,
"decimal_key6": 0,
"decimal_key7": 0,
"decimal_key8": 0,
"decimal_key9": 0,
"decimal_key10": 0,
"decimal_key11": 0,
"decimal_key12": 0,
"decimal_key13": 0,
"decimal_key14": 0,
"decimal_key15": 0,
"decimal_key16": 0,
"decimal_key17": 0,
"decimal_key18": 0,
"decimal_key19": 0,
"decimal_key20": 0
}
}

cURL request

curl --request POST \
--url 'https://{restApiURLAddress}/api/records/clone' \
--header 'Authorization: Bearer {ACCESS_TOKEN}' \
--header 'Content-Type: application/json' \
--data '{
"filter": {
"record_key": "d1c2e12cfeababc8b95daf6902e210b1",
"profile_key": "4274e510a2f41aeb9e8e0f8b56ff6c2",
"range_key": 2000,
"key10": "New",
"key9": "Position",
"key8": "Product Manager",
"key7": null,
"key6": null,
"key5": null,
"key4": "Shipping",
"key3": null,
"key2": null,
"key1": "Additional info",
"key": null,
"body": "{\"name\":\"John\",\"vehicle\":\"Audi\"}",
"created_at": "2023-08-07T07:45:38.256Z",
"updated_at": "2023-08-07T07:45:38.256Z"
},
"update_with": {
"record_key": "d1c6e12cfea6abc4t95daf6902ht10b1",
"profile_key": "4274e510a2fgh572ht0f8b56ff6c2",
"range_key": 5000,
"key10": "New",
"key9": "Position",
"key8": "Product Manager",
"key7": null,
"key6": null,
"key5": null,
"key4": "Shipping",
"key3": null,
"key2": null,
"key1": "Additional info",
"key": null,
"body": "{\"name\":\"John\",\"vehicle\":\"Audi\"}",
"created_at": "2023-08-07T07:45:38.256Z",
"updated_at": "2023-08-07T07:45:38.256Z"
}
}

STATUS 201 - The record has been duplicated successfully.

STATUS 400 - Invalid input parameters have been provided for record lookup or duplication.

STATUS 401 - Access is denied.

STATUS 403 - Partial text-match search is not enable for InCountry Vault.

STATUS 403 - No records matching the filtration criteria have been found.

STATUS 409 - InCountry Vault for the country is not supported.

STATUS 415 - An unsupported request content type.

STATUS 422 - Decryption of records matching the filtration criteria has failed.

STATUS 429 - The number of allowed requests has been exceeded.

STATUS 5** - Server error.

Updating a single record

POST /api/records

info

You can use this request to update the existing records. You need to pass new values for fields that you want to modify, along with old values for fields that you do not want to modify. This request will overwrite the current record’s values with new ones, so if you do not provide old values for specific fields, values in such fields will be cleared.

For the details on this request body, please see the Create a single record request.

ParameterTypeValueDescription
useAliasesquery?useAliases=trueAppend this string to the request address to use key-alias mappings instead of actual record’s keys.
Warning Don’t append anything to use the actual record’s keys.
cURL request

curl --request POST \
--url 'https://{restApiURLAddress}/api/records' \
--header 'Authorization: Bearer {ACCESS_TOKEN}' \
--header 'Content-Type: application/json' \
--data '{
"record_key": "d1c2e12cfeababc8b95daf6902e210b1",
"profile_key": "4274e510a2f41aeb9e8e0f8b56ff6c2",
"range_key": 2000,
"key10": "New",
"key9": "Position",
"key8": "Product Manager",
"key7": null,
"key6": null,
"key5": null,
"key4": "Shipping",
"key3": null,
"key2": null,
"key1": "Additional info",
"key": null,
"body": "{\"name\":\"John\",\"vehicle\":\"Audi\"}",
"country": "se",
"expires_at": "2021-04-07T07:15:44.393Z"
}'

Responses

STATUS 201 - application/json A record has been updated successfully. Returns a record key and record details similar to the data you submitted within the request.

Example

{
"country": "se",
"key": "d1c2e12cfeababc8b95daf6902e210b1",
"record_key": "d1c2e12cfeababc8b95daf6902e210b1",
"profile_key": "4274e510a2f41aeb9e8e0f8b56ff6c2",
"range_key": 2000,
"range_key1": 2000,
"body": "{\"name\":\"John\",\"vehicle\":\"Audi\"}",
"key1": "Additional info",
"key2": "Position",
"key3": "Product Manager",
"key4": "Shipping",
"key5": null,
"key6": null,
"key7": null,
"key8": null,
"key9": null,
"key10": "New",
"expires_at": "2021-04-07T07:15:44.393Z"
}

STATUS 400 - application/json An invalid record has been provided.

STATUS 401 - Access is denied.

STATUS 409 - InCountry Vault for the country is not available.

STATUS 415 - An unsupported request content type.

STATUS 422 - Validation of input parameters has failed.

STATUS 429 - The number of allowed requests has been exceeded.

STATUS 5** - Server error.

Updating multiple records

POST /api/records/batch/update

ParameterTypeValueDescription
useAliasesquery?useAliases=trueAppend this string to the request address to use key-alias mappings instead of actual record’s keys.
Warning Don’t append anything to use the actual record’s keys.

Request body

Please see the example of the request structure.

Example

{
"search_key": "record_key",
"country": "string",
"records": [
{
"key": "string",
"record_key": "string",
"body": "string / string in the JSON format",
"precommit_body": "string",
"profile_key": "string",
"parent_key": "string",
"range_key": 0,
"range_key1": 0,
"range_key2": 0,
"range_key3": 0,
"range_key4": 0,
"range_key5": 0,
"range_key6": 0,
"range_key7": 0,
"range_key8": 0,
"range_key9": 0,
"range_key10": 0,
"service_key1": "string",
"service_key2": "string",
"service_key3": "string",
"service_key4": "string",
"service_key5": "string",
"key1": "string",
"key2": "string",
"key3": "string",
"key4": "string",
"key5": "string",
"key6": "string",
"key7": "string",
"key8": "string",
"key9": "string",
"key10": "string",
"key11": "string",
"key12": "string",
"key13": "string",
"key14": "string",
"key15": "string",
"key16": "string",
"key17": "string",
"key18": "string",
"key19": "string",
"key20": "string",
"expires_at": "2021-04-07T07:15:44.435Z"
},
{
"key": "string",
"record_key": "string",
"body": "string / string in the JSON format",
"precommit_body": "string",
"profile_key": "string",
"parent_key": "string",
"range_key": 0,
"range_key1": 0,
"range_key2": 0,
"range_key3": 0,
"range_key4": 0,
"range_key5": 0,
"range_key6": 0,
"range_key7": 0,
"range_key8": 0,
"range_key9": 0,
"range_key10": 0,
"service_key1": "string",
"service_key2": "string",
"service_key3": "string",
"service_key4": "string",
"service_key5": "string",
"key1": "string",
"key2": "string",
"key3": "string",
"key4": "string",
"key5": "string",
"key6": "string",
"key7": "string",
"key8": "string",
"key9": "string",
"key10": "string",
"key11": "string",
"key12": "string",
"key13": "string",
"key14": "string",
"key15": "string",
"key16": "string",
"key17": "string",
"key18": "string",
"key19": "string",
"key20": "string",
"expires_at": "2021-04-07T07:15:46.435Z"
}
]
}

cURL request

curl --request POST \
--url 'https://{restApiURLAddress}/api/records/batch/update' \
--header 'Authorization: Bearer {ACCESS_TOKEN}' \
--header 'Content-Type: application/json' \
--data '{
"records": [
{
"record_key": "d1c2e12cfeababc8b95daf6902e210b1",
"profile_key": "4274e510a2f41aeb9e8e0f8b56ff6c2",
"range_key": 2000,
"key10": "New",
"key9": null,
"key8": null,
"key7": null,
"key6": null,
"key5": null,
"key4": "Shipping",
"key3": null,
"key2": null,
"key1": "Additional info",
"key": null,
"body": "{\"name\":\"John\",\"vehicle\":\"Audi\"}"
},
{
"record_key": "69f6a71405facac91d002dc9adce85fa",
"profile_key": "baab015f2f9c350ab610fddd3986c53",
"range_key": 3000,
"key10": "New",
"key9": null,
"key8": null,
"key7": null,
"key6": null,
"key5": null,
"key4": "Shipping",
"key3": null,
"key2": null,
"key1": "Additional info",
"key": null,
"body": "{\"name\":\"Alice\",\"vehicle\":\"Mercedes\"}"
}
],
"country": "se"
}'

Responses

STATUS 200 - application/json Records have been updated successfully. Returns record keys and record details similar to data you submitting within the request payload.

Example

[
{
"country": "se",
"key": "d1c2e12cfeababc8b95daf6902e210b1",
"record_key": "d1c2e12cfeababc8b95daf6902e210b1",
"profile_key": "4274e510a2f41aeb9e8e0f8b56ff6c2",
"range_key": 2000,
"range_key1": 2000,
"body": "{\"name\":\"John\",\"vehicle\":\"Audi\"}",
"key1": "Additional info",
"key2": null,
"key3": null,
"key4": "Shipping",
"key5": null,
"key6": null,
"key7": null,
"key8": null,
"key9": null,
"key10": "New"
},
{
"country": "se",
"key": "69f6a71405facac91d002dc9adce85fa",
"record_key": "69f6a71405facac91d002dc9adce85fa",
"profile_key": "baab015f2f9c350ab610fddd3986c53",
"range_key": 3000,
"range_key1": 3000,
"body": "{\"name\":\"Alice\",\"vehicle\":\"Mercedes\"}",
"key1": "Additional info",
"key2": null,
"key3": null,
"key4": "Shipping",
"key5": null,
"key6": null,
"key7": null,
"key8": null,
"key9": null,
"key10": "New"
}
]

STATUS 400 - application/json Invalid records have been provided.

STATUS 401 - Access is denied.

STATUS 401 - Partial text-match search is not enabled for InCuntry Vault.

STATUS 409 - InCountry Vault for the country is not available.

STATUS 415 - An unsupported request content type.

STATUS 422 - Records cannot be processed.

STATUS 429 - The number of allowed requests has been exceeded.

STATUS 5** - Server error.

Searching for records

POST /api/records/find

ParameterTypeValueDescription
useAliasesquery?useAliases=trueAppend this string to the request address to use key-alias mappings instead of actual record’s keys.
Warning Don’t append anything to use the actual record’s keys.

Request body

ParametersTypeExampleDescription
countryISO country code (lowercase)sg (equals to Singapore)Country where a new record is looked up. You can use different countries.
filterobjectSee the example.Specify the criteria for filtration within the filter object.You can look up records by any of record fields. For the full list of supported fields, please see the Available record fields section.
optionsobjectSee the example.Specify the criteria for returning the search results:* limit, offset,sort
limitinteger10Sets the maximal number of search results. It is passed as a part of the options object.
offsetinteger50Specifies the offset (pagination) of records from which the record lookup is performed. It is passed as a part of the options object.
sortarraySpecifies the sorting order of records against a specific field. The sorting can be performed by the following fields:range_keyN, created_at, updated_at, expires_at, keyN. The order in which you specify fields within the sort array will affect the sorting order of records.It is passed as a part of the options object.

Please see the example of the request structure.

Example

{
"country": "string",
"filter": {
"key": "string",
"record_key": "string",
"profile_key": "string",
"range_key": 0,
"range_key1": 0,
"range_key2": 0,
"range_key3": 0,
"range_key4": 0,
"range_key5": 0,
"range_key6": 0,
"range_key7": 0,
"range_key8": 0,
"range_key9": 0,
"range_key10": 0,
"key1": "string",
"key2": "string",
"key3": "string",
"key4": "string",
"key5": "string",
"key6": "string",
"key7": "string",
"key8": "string",
"key9": "string",
"key10": "string",
"key11": "string",
"key12": "string",
"key13": "string",
"key14": "string",
"key15": "string",
"key16": "string",
"key17": "string",
"key18": "string",
"key19": "string",
"key20": "string",
"service_key1": "string",
"service_key2": "string",
"service_key3": "string",
"service_key4": "string",
"service_key5": "string",
"version": 0,
"search_keys": "string"
},
"options": {
"limit": 0,
"offset": 0,
"sort": [
{
"range_key1": "asc"
},
{
"range_key2": "asc"
},
{
"range_key3": "asc"
},
{
"range_key4": "asc"
},
{
"range_key5": "asc"
},
{
"range_key6": "asc"
},
{
"range_key7": "asc"
},
{
"range_key8": "asc"
},
{
"range_key9": "asc"
},
{
"range_key10": "asc"
},
{
"created_at": "asc"
},
{
"updated_at": "asc"
},
{
"expires_at": "asc"
},
{
"key1": "asc"
},
{
"key2": "asc"
},
{
"key3": "asc"
},
{
"key4": "asc"
},
{
"key5": "asc"
},
{
"key6": "asc"
},
{
"key7": "asc"
},
{
"key8": "asc"
},
{
"key9": "asc"
},
{
"key10": "asc"
},
{
"key11": "asc"
},
{
"key12": "asc"
},
{
"key13": "asc"
},
{
"key14": "asc"
},
{
"key15": "asc"
},
{
"key16": "asc"
},
{
"key17": "asc"
},
{
"key18": "asc"
},
{
"key19": "asc"
},
{
"key20": "asc"
}
]
}
}

Example

{
  "country": "sg",
  "filter": {
    "key1": ["k1234", "k1235"],
    "key2": ["John", "Jane"]
  },
"options": {
"limit": 10,
"offset": 50
}
}

or

{
"country": "sg",
"filter": {
"search_keys": "abc"
}
}

or

{
"country": "sg",
"filter": {
"search_keys": "abc",
"range_key1": [1, 2]
}
}

cURL request

//FINDS A RECORD BY THE SPECIFIED CRITERIA

curl --request POST \
--url 'https://{restApiURLAddress}/api/records/find' \
--header 'Authorization: Bearer {ACCESS_TOKEN}' \
--header 'Content-Type: application/json' \
--data '{
"country": "se",
"filter": {
"range_key": 3000,
"key4": "Shipping",
"profile_key": "baab015f2f9c350ab610fddd3986c53",
"record_key": "69f6a71405facac91d002dc9adce85fa"
},
"options": {
"limit": 10,
"offset": 0
}
}'

//FINDS RECORDS THAT HAVE THE range_key FIELD WITHIN =} 1000 AND {= 4000 RANGE

curl --request POST \
--url 'https://{restApiURLAddress}/api/records/find' \
--header 'Authorization: Bearer {ACCESS_TOKEN}' \
--header 'Content-Type: application/json' \
--data '{
"country": "se",
"filter": {
"range_key": {"$gte":1000, "$lte":4000},
"key4": "Shipping",
"profile_key": "baab015f2f9c350ab610fddd3986c53",
"record_key": "69f6a71405facac91d002dc9adce85fa"
},
"options": {
"limit": 10,
"offset": 0
}
}'

//FINDS RECORDS WHOSE THE range_key FIELD TAKES ONE OF THE SPECIFIED VALUES

curl --request POST \
--url 'https://{restApiURLAddress}/api/records/find' \
--header 'Authorization: Bearer {ACCESS_TOKEN}' \
--header 'Content-Type: application/json' \
--data '{
"country": "se",
"filter": {
"range_key": [1000, 4000],
"key4": "Shipping",
"profile_key": "baab015f2f9c350ab610fddd3986c53",
"record_key": "69f6a71405facac91d002dc9adce85fa"
},
"options": {
"limit": 10,
"offset": 0
}
}'

//FINDS RECORDS AND SORTS THEM BY FIELD IN ASCENDING/DESCENDING ORDER

curl --request POST \
--url 'https://{restApiURLAddress}/api/records/find' \
--header 'Authorization: Bearer {ACCESS_TOKEN}' \
--header 'Content-Type: application/json' \
--data '{
"country": "se",
"filter": {
"range_key": [1000, 4000],
"key4": "Shipping",
"profile_key": "baab015f2f9c350ab610fddd3986c53",
"record_key": "69f6a71405facac91d002dc9adce85fa"
},
"options": {
"limit": 10,
"offset": 0,
"sort":[{"key1":"asc"}, {"key2": "desc"}]
}
}'

Responses

STATUS 200 - application/json Returns information about the found record or records.

This status is also returned when no records matching the search criteria are found.

Example

{
"data": [
{
"country": "se",
"key": "69f6a71405facac91d002dc9adce85fa",
"record_key": "69f6a71405facac91d002dc9adce85fa",
"parent_key": null,
"profile_key": "baab015f2f9c350ab610fddd3986c53",
"range_key": 3000,
"range_key1": 3000,
"range_key2": null,
"range_key3": null,
"range_key4": null,
"range_key5": null,
"range_key6": null,
"range_key7": null,
"range_key8": null,
"range_key9": null,
"range_key10": null,
"body": "{\"name\":\"Alice\",\"vehicle\":\"Mercedes\"}",
"precommit_body": null,
"key1": "Additional info",
"key2": null,
"key3": null,
"key4": "Shipping",
"key5": null,
"key6": null,
"key7": null,
"key8": null,
"key9": null,
"key10": "New",
"key11": null,
"key12": null,
"key13": null,
"key14": null,
"key15": null,
"key16": null,
"key17": null,
"key18": null,
"key19": null,
"key20": null,
"service_key1": null,
"service_key2": null,
"attachments": [],
"created_at": "2021-03-26T11:57:45.000Z",
"updated_at": "2021-03-26T11:57:45.000Z",
"version": 0
}
],
"meta": {
"count": 1,
"limit": 10,
"offset": 0,
"total": 1
}
} "updated_at": "2020-11-21T12:05:28.000Z"
}
],
"meta": {
"count": 2,
"limit": 100,
"offset": 0,
"total": 2
}
}

STATUS 400 - Incorrect filtration parameters or options have been specified.

STATUS 401 - Access is denied.

STATUS 401 - Partial text-match search is not enabled for InCuntry Vault.

STATUS 409 - InCountry Vault for the country is not available.

STATUS 415 - An unsupported request content type.

STATUS 422 - Validation of input parameters has failed.

STATUS 429 - The number of allowed requests has been exceeded.

STATUS 5** - Server error.

Aggregating records

POST /api/records/aggregate

ParameterTypeValueDescription
useAliasesquery?useAliases=trueAppend this string to the request address to use key-alias mappings instead of actual record’s keys.
Warning Don’t append anything to use the actual record’s keys.

Please see the example of the request structure.

Example

{
"next": "string",
"metrics": {
"additionalProp1": {
"func": "sum",
"key": "string"
},
"additionalProp2": {
"func": "sum",
"key": "string"
},
"additionalProp3": {
"func": "sum",
"key": "string"
}
},
"filter": {
"key": "string",
"record_key": "string",
"profile_key": "string",
"parent_key": "string",
"range_key": 0,
"range_key1": 0,
"range_key2": 0,
"range_key3": 0,
"range_key4": 0,
"range_key5": 0,
"range_key6": 0,
"range_key7": 0,
"range_key8": 0,
"range_key9": 0,
"range_key10": 0,
"key1": "string",
"key2": "string",
"key3": "string",
"key4": "string",
"key5": "string",
"key6": "string",
"key7": "string",
"key8": "string",
"key9": "string",
"key10": "string",
"key11": "string",
"key12": "string",
"key13": "string",
"key14": "string",
"key15": "string",
"key16": "string",
"key17": "string",
"key18": "string",
"key19": "string",
"key20": "string",
"key21": "string",
"key22": "string",
"key23": "string",
"key24": "string",
"key25": "string",
"service_key1": "string",
"service_key2": "string",
"service_key3": "string",
"service_key4": "string",
"service_key5": "string",
"version": 0,
"search_keys": "string",
"created_at": "2022-08-30T07:41:54.490Z",
"updated_at": "2022-08-30T07:41:54.490Z"
},
"group_by": {
"limit": 0,
"keys": [
"string"
]
}
}

Within the metrics section, you can define the aggregation parameters:

ArgumentDescription
additionalPropNYou can declare the aggregated metric, for example, total_sales_amount, record_count, or total_revenue.
funcYou can define the aggregation function to apply:count - cannot take additional arguments. Counts the number of records.sum - can take additional arguments. Summarizes values against a specific record’s key. You need to pass additional argument for summarization:* key - the record’s key name which values should be summarized. Only numeric fields (range_keyN) can be summarized.
nextYou can use the pagination when the number of groups within the returned aggregation exceeds 100 groups. In this case, the REST API will return the next value in the first response. You need to use this value to query the next batch of groups and update this value with the value from the prior response every time you query a subsequent batch of groups.
cURL request

curl --request POST \
--url 'https://{restApiURLAddress}/api/records/aggregate' \
--header 'Authorization: Bearer {ACCESS_TOKEN}' \
--header 'Content-Type: application/json' \
--data '{
"metrics": {
"total_revenue": {
"func": "sum",
"key": "range_key3"
},
"total_tax": {
"func": "sum",
"key": "range_key4"
},
"transaction_count": {
"func": "count"
}
},
"filter": {
"range_key2": {"$gte":1000, "$lte":4000},
"key4": "Order with Shipping"
},
"options": {
"limit": 100,
"offset": 0
}
}'

//URL EXAMPLE
https://se-restapi-mt-01.incountry.io/api/records/aggregate

When you query the next batch of groups within the aggregation, you can pass only the next value within the request:

curl --request POST \
--url 'https://{restApiURLAddress}/api/records/aggregate' \
--header 'Authorization: Bearer {ACCESS_TOKEN}' \
--header 'Content-Type: application/json' \
--data '{
"next": "ZGluZyBkb25nIGNoaW5nIGNob25n",
}'

//URL EXAMPLE
https://se-restapi-mt-01.incountry.io/api/records/aggregate

Responses

STATUS 200 - JSON This response returns the results of aggregation and summarization.

Example

{
"data": {
"additionalProp1": {
"group": {
"keys": {
"additionalProp1": "string",
"additionalProp2": "string",
"additionalProp3": "string"
}
},
"metrics": {
"additionalProp1": 0,
"additionalProp2": 0,
"additionalProp3": 0
}
},
"additionalProp2": {
"group": {
"keys": {
"additionalProp1": "string",
"additionalProp2": "string",
"additionalProp3": "string"
}
},
"metrics": {
"additionalProp1": 0,
"additionalProp2": 0,
"additionalProp3": 0
}
},
"additionalProp3": {
"group": {
"keys": {
"additionalProp1": "string",
"additionalProp2": "string",
"additionalProp3": "string"
}
},
"metrics": {
"additionalProp1": 0,
"additionalProp2": 0,
"additionalProp3": 0
}
}
},
"meta": {
"next": "string"
},
"errors": [
"string"
]
}

STATUS 400 - Incorrect filtration parameters or options have been specified.

STATUS 401 - Access is denied.

STATUS 401 - Partial text-match search is not enabled for InCuntry Vault.

STATUS 409 - InCountry Vault for the country is not available.

STATUS 415 - An unsupported request content type.

STATUS 422 - Validation of input parameters has failed.

STATUS 429 - The number of allowed requests has been exceeded.

STATUS 5** - Server error.

Deleting a record

DELETE /api/records/{country}/{record_key}

Request parameters

ParametersTypeValueDescription
countryISO country code (lowercase)sgCountry where the record is stored.
record_keystring/arrayk1234Unique primary key (record_key) for record identification
cascadeBystring (query){profile_key} or {record_key}This parameter initiates the cascade removal of child records that pertain to the parent record.
cURL request

curl --request DELETE \
--url 'https://{restApiURLAddress}/api/records/{country}/{record_key}&cascadeBy={record_key}' \
--header 'Authorization: Bearer {ACCESS_TOKEN}' \

//URL EXAMPLE
https://se-restapi-mt-01.incountry.io/api/records/se/d1c2e12cfeababc8b95daf6902e210b1

Responses

STATUS 204 - plain The record has been successfully deleted.

STATUS 400 - Invalid query parameters have been specified.

STATUS 401 - Access is denied.

STATUS 404 - The record has not been found.

STATUS 409 - InCountry Vault for the country is not available.

STATUS 429 - The number of allowed requests has been exceeded.

STATUS 5** - Server error.

Deleting multiple records

POST /api/records/batch/delete

ParameterTypeValueDescription
useAliasesquery?useAliases=trueAppend this string to the request address to use key-alias mappings instead of actual record’s keys.
Warning Don’t append anything to use the actual record’s keys.

Request body

ParametersTypeExampleDescription
filterobjectSee the example.Specify the criteria for deletion within the filter object. Currently only deletion by record_key is supported.
record_keyarraySee the example.Array of records that are subject to removal.

Please see the example of the request structure.

Example

{
"filter": {
"record_key": [
"string"
]
}
}

cURL request

curl --request POST \
--url 'https://{restApiURLAddress}/api/records/batch/delete' \
--header 'Authorization: Bearer {ACCESS_TOKEN}' \
--header 'Content-Type: application/json' \
--data '{
"filter": {
"record_key": [
"d1c2e12cfeababc8b95daf6902e210b1",
"d1cg88ecfeababc8b95daf690g4210b1",
"f7fg88ecfeababc8b95daf690gf8s7dd"
]
}

//URL EXAMPLE
https://se-restapi-mt-01.incountry.io/api/records/batch/delete

Responses

STATUS 204 - plain Records have been successfully deleted.

STATUS 400 - An invalid input has been provided.

STATUS 401 - Access is denied.

STATUS 404 - No records matching filtration criteria have been found.

STATUS 409 - InCountry Vault for the country is not available.

STATUS 415 - An unsupported request content type.

STATUS 422 - An unsupported request content type.

STATUS 429 - The number of allowed requests has been exceeded.

STATUS 5** - Server error.

Rehashing values of a record

Recalculates tokens or hashes for a record’s fields. You can recalculate tokens or hashes for all values within a record or just specific fields.

POST /api/records/rehash

Request body

ParametersTypeExampleDescription
dtkstringDTK key (96-character alphanumeric)Specify the deterministic tokenization key (DTK).
keysstring[] (array of values)Specify one or multiple profile_key of records that you want to retokenize or rehash.
rulesarraySpecify fields and redaction algorithms for recalculation. See the request example for details and the list of supported functions.

Please see the example of the request structure.

Example

{
dtk: '{DETERMINISTIC_TOKENIZATION_KEY}',
keys: [
'{profile_key1}',
'{profile_key2}',
],
rules: {
{field_name}: {
strategy: '{strategy_name}',
strategyOptions: {
{LIST_STRATEGY_OPTIONS}
}
}

cURL request

curl --request POST \
--url 'https://{restApiURLAddress}/api/records/rehash' \
--header 'Authorization: Bearer {ACCESS_TOKEN}' \
--header 'Content-Type: application/json' \
--data '{
dtk: 'some_deterministic_key',
keys: [
'pk1',
'pk2',
],
rules: {
first_name: {
strategy: 'alphaNumeric',
},
nickname: {
strategy: 'masking',
strategyOptions: {
type: 'alphanumeric',
},
},
address: {
strategy: 'alphaNumericPersistent',
strategyOptions: {
length: 20,
},
},
email: {
strategy: 'formula',
strategyOptions: {
formula: {
fn: 'dtkSha256',
transforms: [
'trim',
'toLowerCase',
],
format: '[A-Za-z0-9]{15}@redacted.com',
},
},
},
age: {
strategy: 'numeric',
},
service_key: {
strategy: 'fixed',
strategyOptions: {
value: 'fixed_value',
},
},
null_field: {
strategy: 'alphaNumericPersistent',
strategyOptions: {
length: 20,
},
},
},
};
}

//URL EXAMPLE
https://se-restapi-mt-01.incountry.io/api/records/rehash

Supported functions

Redaction strategy(tokenization or rehashing function)Strategy optionsDescription
alphaNumericlength: 32The default length is 32. You can change for any other length.Applies an alpha-numeric hash to a string containing letters and numbers. The produced alphanumeric string varies during every redaction.
alphaNumericLowerCaselength: 32The default length is 32. You can change for any other length.Applies a lower-case alphanumeric hash to a string containing letters and numbers.
alphaPrependedlength: 32The default length is 32. You can change for any other length.Applies a prefix comprised of a single letter.
emaillength: 20Applies an email-pattern string, e.g. dsf34fsdf@redactedemail.com. The produced email-pattern string varies during every redaction.
plainn/aForwards the original value.
onen/aApplies '1' ( a single digit).
zeron/aApplies '0' (a single digit).
numericn/aApplies a random numeric value of the length equal to the original value.
dateISOn/aApplies a random date in the ISO format.
defaultDateISOn/aApplies a default date in the default ISO format (1970-01-01T00:00:00Z).
fixedvalue: 'fixed_value'Applies any hardcoded value. If you select this option, in the Value box, enter the value that should be applied by default.
alphaNumericPersistentlength: 20(value from the 1-64 range is acceptable)Applies an alpha-numeric hash that remains the same for the same alphanumeric string during every redaction.
emailPersistentlength: 20(value from the 20-64 range is acceptable)Applies an email-pattern string that remains the same for the same email address during every redaction.
formula

formula: {
fn: 'dtkSha256' or 'sha256',
transforms: [
'trim',
'toLowerCase',
],
format: '[A-Za-z0-9]{15}@redacted.com',
}
Applies a formula that can be tailored to product a value matching a specific format.
maskingtype: 'alphanumeric' or 'email'Masks the value depending on the input value and type.

Responses

STATUS 200 - Records have been successfully rehashed.

STATUS 400 - Incorrect records have been provided.

STATUS 401 - Access is denied.

STATUS 415 - An unsupported request content type.

STATUS 419 - Records have not been synchronized with InCountry Vault.

STATUS 429 - The number of allowed requests has been exceeded.

STATUS 5** - Server error.

Management of attachments

InCountry DRaaS provides two storages for storing attachments:

  • database storage - a proprietary large object storage on the basis of the PostgreSQL database.

  • object storage - a generic S3 cloud object storage that integrates with the InCountry DRaaS. Currently, only Alibaba Cloud object storage is supported.

You can manage attachments stored in the InCountry Vault, as follows:

Available attachment fields

note

This fields are available for attachments stored in the database storage only.

FieldTypeSpecifics
file_idstringUnique identifier of an attachment.
filenamestringName of an attachment.
hashstringHash of f an attachment.
mime_typestringMIME type of an attachment.
sizestringSize of an attachment in bytes.
created_atstring(date-time)Timestamp when an attachment was uploaded to the InCountry Vault.
updated_atstring(date-time)Timestamp when an attachment was updated in the InCountry Vault.
download_linkstringLink to download an attachment from the InCountry Vault.

Uploading attachments (database)

POST ​/api​/records​/{country}​/{record_key}​/files

Request parameters

All the request parameters are required.

ParametersTypeValueDescription
countrystring (ISO country code (lowercase))sgCountry which a new attachment is uploaded to.
record_keystringatt1234A key of the record which the attachment is associated with.
filestring@company_logo.png;type=image/pngA name of the attachment for upload.

The request body should be a binary string of the file you are uploading.

cURL request

curl --request POST \
--url 'https://{restApiURLAddress}/api/records/{country}/{id}/files' \
--header 'Authorization: Bearer {ACCESS_TOKEN}' \
--header 'Content-Type: multipart/form-data; boundary=---011000010111000001101001' \
--header 'x-filename: file_name.{extension}'
--form 'file=@"{file local path}"'

//URL EXAMPLE
https://se-restapi-mt-01.incountry.io/api/records/se/d1c2e12cfeababc8b95daf6902e210b1/files

//LOCAL PATH TO FILE EXAMPLE
--form 'file=@"/Users/John/Projects/files/index.html"'

Responses

STATUS 201 - JSON The attachment has been successfully uploaded.

Example

{
"file_id": "5416a334-6ce6-4e3b-9a0d-464cb417c094",
"filename": "index.html",
"hash": "78701b482fc9738e26f32254bbe7d71990f5025a9b728046a280a3822cdf5cad",
"mime_type": "application/x-sh",
"size": 279,
"created_at": "2021-03-26T11:36:44.000Z",
"updated_at": "2021-03-26T11:36:44.000Z",
"download_link": "https://se-mt-01.incountry.io/v2/storage/records/se/310459560d9e757d6e51be45a5aad862fbb81c52d72a026e75d21366ac223a40/attachments/5416a334-6ce6-4e3b-9a0d-464cb417c094"
}

STATUS 400 - An invalid file has been provided.

STATUS 401 - Access is denied.

STATUS 403 - File storage is not available.

STATUS 404 - The target record has not been found.

STATUS 409 - File storage for the country is not available.

STATUS 413 - The request payload exceeds the maximal size.

STATUS 415 - An unsupported request content type.

STATUS 422 - Validation of input parameters has failed.

STATUS 429 - The number of allowed requests has been exceeded.

STATUS 5** - Server error.

Uploading attachments (object storage)

To upload your attachment, first, you need to receive the upload URL and parameters using the following endpoint:

POST /api/records/{record_key}/attachments/upload-url

Request parameters

All the request parameters are required.

ParametersTypeValueDescription
record_keystringatt1234A record key of the record which the attachment is associated with.

Within the request body, you need to pass two parameters, as follows:

ParametersTypeValueDescription
expirationinteger60Time to expiration of the upload URL issued by the object storage for file upload. The minimal value is 30 seconds, maximal value is 32,400 seconds.
filenamestringoriginal_file_name_to_save.txtName of the file which you want to upload to the object storage.
cURL request

curl --request POST \
--url 'https://{restApiURLAddress}/api/records/{record_key}/attachments/upload-url' \
--header 'Authorization: Bearer {ACCESS_TOKEN}' \
--data '{
"expiration": 60,
"filename": "original_file_name_to_save.txt"
}'

// URL EXAMPLE
https://se-restapi-mt-01.incountry.io/api/records/x56s5f98fs98f/attachments/upload-url

Responses

STATUS 200 - JSON The upload URL with upload parameters was created successfully.

Example

{
"action": "string",
"file_id": "string",
"method": "string",
"form_data": {
"key": "string",
"Expires": "2022-11-17T13:07:56.608Z",
"policy": "string",
"Signature": "string",
"OSSAccessKeyId": "string",
"x-oss-security-token": "string",
"callback": "string",
"success_action_status": "string",
"Content-Disposition": "string"
}
}

This endpoint returns the form action (URL to upload an attachment (POST)) and form data parameters for attachment upload using the PostObject operation. Then you must construct the PostObject request using the received response (detailed in the Responses section) and pass all form_data parameters with the file itself. See the example of the request below:

Example

POST / HTTP/1.1
Host: incountry-attachments-uuid1.oss-cn-shanghai.aliyuncs.com
Content-Length: 344606
Content-Type: multipart/form-data; boundary=9431149156168

--9431149156168
Content-Disposition: form-data; name="key"
5a5c698a-8117-4725-a4bf-7dfa5f36f2ef/awesomerecordkey/tony-eos-546-file1-test2

--9431149156168
Content-Disposition: form-data; name="Expires"
2022-11-17T13:07:56.608Z

--9431149156168
Content-Disposition: form-data; name="success_action_status"
200

--9431149156168
Content-Disposition: form-data; name="OSSAccessKeyId"
STS.NUUfc27****

--9431149156168
Content-Disposition: form-data; name="policy"
eyJleHBpcmF0aW9uIjoiMjAyMi0xMS0xN1QxMzowNzo1Ni42MDhaIiwiY29uZGl0aW9ucyI6W3siYnVja2V0IjoiaW5jb3VudHJ5LWF0dGFjaG1lbnRzLXV1aWQxIn0sWyJjb250ZW50LWxlbmd0aC1yYW5nZSIsMSwxMDQ4NTc2MDBdLFsiZXEiLCIka2V5IiwiNWE1YzY5OGEtODExNy00NzI1LWE0YmYtN2RmYTVmMzZmMmVmL2F3ZXNvbWVyZWNvcmRrZXkvdG9ueS1lb3MtNTQ2LWZpbGUxLXRlc3QyIl0sWyJlcSIsIiRzdWNjZXNzX2FjdGlvbl9zdGF0dXMiLCIyMDAiXSx7ImNhbGxiYWNrIjoiZXlKallXeHNZbUZqYTFWeWJDSTZJbWgwZEhCek9pOHZQSEpsYzNSaGNHbGZhRzl6ZEQ0dllYQnBMM0psWTI5eVpITXZQR052ZFc1MGNuaytMenh5WldOdmNtUmZhMlY1UGk5aGRIUmhZMmh0Wlc1MGN5OWpZV3hzWW1GamF5SXNJbU5oYkd4aVlXTnJRbTlrZVNJNkludGNJblpsYm1SdmNsd2lPaUJjSW1Gc2FWd2lMQ0JjSW1KMVkydGxkRndpT2lCY0lpUjdZblZqYTJWMGZWd2lMQ0JjSW05aWFtVmpkRndpT2lCY0lpUjdiMkpxWldOMGZWd2lMQ0JjSW5OcGVtVmNJam9nWENJa2UzTnBlbVY5WENJc0lGd2liV2x0WlZSNWNHVmNJam9nWENJa2UyMXBiV1ZVZVhCbGZWd2lmU0lzSW1OaGJHeGlZV05yUW05a2VWUjVjR1VpT2lKaGNIQnNhV05oZEdsdmJpOXFjMjl1SW4wPSJ9XX0=

--9431149156168
Content-Disposition: form-data; name="Signature"
Cn7t9Cz70aby****

--9431149156168
Content-Disposition: form-data; name="x-oss-security-token"
CAIS9wF1q6Ft5B2yfSjIr5bgLdmG2plsjpqvZGThjG8SdPdD14nNhTz2IHtNfXVpAugZs************

--9431149156168
Content-Disposition: form-data; name="callback"
eyJjYWxsYmFja1VybCI6Imh0dHA6Ly8yNmIxLTMxLTIyMy0xMjQtMTQ2Lm5ncm9rLmlvL2NhbGxiYWNrIiwiY2FsbGJhY2tCb2R5Ijoie1widmVuZG9yXCI6IFwiYWxpXCIsIFwiYnVja2V0XCI6ICR7YnVja2V0fSwgXCJvYmplY3RcIjogJHtvYmplY3R9LCBcInNpemVcIjogJHtzaXplfSwgXCJtaW1lVHlwZVwiOiAke21pbWVUeXBlfSwgXCJldGFnXCI6ICR7ZXRhZ319IiwiY2FsbGJhY2tCb2R5VHlwZSI6ImFwcGxpY2F0aW9uL2pzb24ifQ==

--9431149156168
Content-Disposition: form-data; name="Content-Disposition"
attachment;filename=original_file_name_to_save.txt

--9431149156168
Content-Disposition: form-data; name="file"; filename="original_file_name_to_save.txt"
Content-Type: text/plain
abcdefg

--9431149156168--

Warning
  • The last form field must be the file. No particular order is required for other form fields.

  • The key of a form field cannot exceed 8 KB and the value of a form field cannot exceed 2 MB.

STATUS 400 - Invalid file data has been provided.

STATUS 401 - Access is denied.

STATUS 404 - The record with the provided record key has not been found.

STATUS 409 - The object storage for the requested country is not supported.

STATUS 415 - An unsupported request content type.

STATUS 422 - The request parameters have not passed validation.

STATUS 429 - Too many requests have been executed.

STATUS 5** - Server error.

Downloading attachments (database)

GET ​/api/records/{country}/{record_key}/files/{file_id}

Request parameters

All the request parameters are required.

ParametersTypeValueDescription
countrystring (ISO country code (lowercase))sgCountry where the attachment is stored.
record_keystringatt1234A record key of the record which the attachment is associated with.
file_idstring (binary)The file identifier of the attachment stored on the InCountry platform.
cURL request

curl --request GET \
--url 'https://{restApiURLAddress}/api/records/{country}/{id}/files/{file_id}' \
--header 'Authorization: Bearer {ACCESS_TOKEN}' \

//URL EXAMPLE
https://se-restapi-mt-01.incountry.io/api/records/se/d1c2e12cfeababc8b95daf6902e210b1/files/d4f0a504-82a6-40b7-b153-1ec81d2f5ae0

Responses

STATUS 200 - plain The file has been passed for download

Example

{
"file_id": "string",
"filename": "string",
"hash": "string",
"mime_type": "string",
"size": 0,
"created_at": "2021-02-10T07:29:32.611Z",
"updated_at": "2021-02-10T07:29:32.611Z",
"download_link": "string"
}

STATUS 401 - Access is denied.

STATUS 403 - File storage is not available or insufficient permissions.

STATUS 404 - The target record or file has not been found.

STATUS 422 - Validation of input parameters has failed.

STATUS 429 - The number of allowed requests has been exceeded.

STATUS 5** - Server error.

Downloading attachments (object storage)

This endpoint creates and returns the download URL for attachment downloading, with it metadata in the response. To download the attachment, you need then to perform a GET request against the download_url value from the response.

GET ​/api/records/{record_key}/attachments/{attachment_id}/download-url?expiration=60

Request parameters

The record_key and file_id request parameters are required.

ParametersTypeValueDescription
record_keystringatt1234A record key of the record which the attachment is associated with.
file_idstringdfjfd87897fs4d6Identifier of the attached file you want to download.
expirationinteger60Time to expiration of the download URL issued by the object storage for file upload. The minimal value is 30 seconds, the maximal value is 32,400 seconds.
cURL request

curl --request GET \
--url 'https://{restApiURLAddress}​/api/records/{record_key}/attachments/{file_id}/download-url?expiration=60' \
--header 'Authorization: Bearer {ACCESS_TOKEN}' \

//URL EXAMPLE
https://se-restapi-mt-01.incountry.io​/api/records/f5ds4687s7t9e7te/attachments/e45r87er98ere78/download-url?expiration=60

Responses

STATUS 200 - JSON The attachment downloading URL with metadata was received successfully.

Example

{
"download_url": "string",
"expires": "2023-06-27T09:28:21.021Z",
"created_at": "2023-06-27T09:28:21.021Z",
"file_id": "string",
"filename": "string",
"mime_type": "string",
"size": 0,
"hash": "string",
"updated_at": "2023-06-27T09:28:21.021Z",
"download_link": "string",
"vendor": "string"
}

STATUS 401 - Access is denied.

STATUS 404 - The record with the provided record key has not been found.

STATUS 409 - The object storage for the requested country is not supported.

STATUS 415 - An unsupported request content type.

STATUS 422 - The request parameters have not passed validation.

STATUS 429 - Too many requests have been executed.

STATUS 5** - Server error.

Updating an attachment (object storage)

Warning

To update the uploaded attachment, you must follow the same steps as when uploading a new file and specify the already created file_id in the request for upload-url.

POST /api/records/{record_key}/attachments/{file_id}/upload-url

Request parameters

All the request parameters are required.

ParametersTypeValueDescription
record_keystringatt1234A record key of the record which the attachment is associated with.
file_idstringdfjfd87897fs4d6Identifier of the attached file you want to download.

Within the request body, you need to pass two parameters, as follows:

ParametersTypeValueDescription
expirationinteger60Time to expiration of the upload URL issued by the object storage for file upload. The minimal value is 30 seconds, maximal value is 32,400 seconds.
filenamestringoriginal_file_name_to_save.txtName of the file which you want to upload to the object storage.
cURL request

curl --request POST \
--url 'https://{restApiURLAddress}/api/records/{record_key}/attachments/{file_id}/upload-url' \
--header 'Authorization: Bearer {ACCESS_TOKEN}' \
--data '{
"expiration": 60,
"filename": "original_file_name_to_save.txt"
}'

//URL EXAMPLE
https://se-restapi-mt-01.incountry.io/api/records/fd4s7f97s9e7r9d9fs/attachments/sfd98f7s98d7fsd7/upload-url

Responses

STATUS 200 - JSON The upload URL with upload parameters was created successfully.

Example

{
"action": "string",
"file_id": "string",
"method": "string",
"form_data": {
"key": "string",
"Expires": "2023-06-27T10:20:27.091Z",
"policy": "string",
"Signature": "string",
"OSSAccessKeyId": "string",
"x-oss-security-token": "string",
"callback": "string",
"success_action_status": "string",
"Content-Disposition": "string"
}
}

STATUS 400 - Invalid file data has been provided.

STATUS 401 - Access is denied.

STATUS 404 - The record with the provided record key has not been found.

STATUS 409 - The object storage for the requested country is not supported.

STATUS 415 - An unsupported request content type.

STATUS 422 - The request parameters have not passed validation.

STATUS 429 - Too many requests have been executed.

STATUS 5** - Server error.

Moving attachments between records (database)

POST ​/api/records/{source_record_key}/files/move/{destination_record_key}

Request parameters

All the request parameters are required.

ParametersTypeValueDescription
source_record_keystringd1c2e12cfeababc8b95daf6902e210b1Key of the record from which the attachment is moved.
destination_record_keystringd1c2e12cfd454ababc8b95daf6902e210b1Key of the record to which the attachment is moved.

Request body

Within the request body, you need to specify the list of attachment identifiers for moving between the specified source and destination records.

{
"attachment_ids": [
"string"
]
}
cURL request

curl --request POST \
--url '​/api/records/{source_record_key}/files/move/{destination_record_key}' \
--header 'Authorization: Bearer {ACCESS_TOKEN}' \
--data '{
"attachment_ids": [
"string"
]
}

//URL EXAMPLE
https://se-restapi-mt-01.incountry.io/api/records/fd4s7f97s9e7r9d9fs/files/move/sfd98f7s98d7fsd7

Responses

STATUS 204 - Attachments have been successfully moved.

STATUS 401 - One of the attachment identifiers is not accessible.

STATUS 401 - Access is denied.

STATUS 403 - File storage is not available.

STATUS 404 - One of the records has not been found.

STATUS 422 - Validation of input parameters has failed.

STATUS 429 - The number of allowed requests has been exceeded.

STATUS 5** - Server error.

Deleting attachments (database)

DELETE ​/api/records/{country}/{record_key}/files/{file_id}

Request parameters

All the request parameters are required.

ParametersTypeValueDescription
countrystring (ISO country code (lowercase))sgCountry where the attachment is stored.
keystringatt1234A record key of the attachment.
file_idstringThe file identifier of the attachment stored in InCountry Vault.
cURL request

curl --request DELETE \
--url 'https://{restApiURLAddress}/api/records/{country}/{id}/files/{file_id}' \
--header 'Authorization: Bearer {ACCESS_TOKEN}' \

// URL EXAMPLE
https://se-restapi-mt-01.incountry.io/api/records/se/d1c2e12cfeababc8b95daf6902e210b1/files/d4f0a504-82a6-40b7-b153-1ec81d2f5ae0

Responses

STATUS 204 - The attachment has been successfully deleted.

STATUS 401 - Access is denied.

STATUS 403 - File storage is not available.

STATUS 404 - The target record or file has not been found.

STATUS 422 - Validation of input parameters has failed.

STATUS 429 - The number of allowed requests has been exceeded.

STATUS 5** - Server error.

Deleting attachments (object storage)

This method deletes all attachments pertaining for a specific record in the object storage.

DELETE ​/api/records/{record_key}/attachments

Request parameters

All the request parameters are required.

ParametersTypeValueDescription
record_keystringatt1234A record key of the attachment.
cURL request

curl --request DELETE \
--url 'https://{restApiURLAddress}/api/records/{record_key}/attachments' \
--header 'Authorization: Bearer {ACCESS_TOKEN}' \

// URL EXAMPLE
https://se-restapi-mt-01.incountry.io/api/records/fsd7f9s8d7f98s7df8/attachments

Responses

STATUS 204 - Attachments have been successfully deleted.

STATUS 401 - Access is denied.

STATUS 404 - The record with the provided record key has not been found.

STATUS 409 - The object storage for the requested country is not supported.

STATUS 415 - An unsupported request content type.

STATUS 422 - Validation of input parameters has failed.

STATUS 429 - The number of allowed requests has been exceeded.

STATUS 5** - Server error.

Querying attachments for a specific record (object storage)

GET ​/api/records/{record_key}/attachments

Request parameters

ParametersTypeValueDescription
record_keystringatt1234A record key of the attachment.
offsetinteger10Offset is the position in the dataset of a particular record. By specifying offset, you retrieve a subset of records starting with the offset value. Offset normally works with limit.
limitinteger100Limit determines how many records to retrieve starting from the offset.
cURL request

curl --request GET \
--url 'https://{restApiURLAddress}/api/records/{record_key}/attachments?limit=100&offset=0' \
--header 'Authorization: Bearer {ACCESS_TOKEN}' \

// URL EXAMPLE
https://se-restapi-mt-01.incountry.io/api/records/fsd456fsd8f4d54f/attachments?limit=100&offset=50

Responses

STATUS 200 - JSON The list of attachments pertaining to a specific record is returned.

STATUS 401 - Access is denied.

STATUS 404 - The record with the provided record key has not been found.

STATUS 409 - The object storage for the requested country is not supported.

STATUS 415 - An unsupported request content type.

STATUS 422 - Validation of input parameters has failed.

STATUS 429 - The number of allowed requests has been exceeded.

STATUS 5** - Server error.

Frontend-initiated requests

This section provides general information on frontend-initiated requests and lists the REST API endpoints that can be called from the application frontend using its specific request authorization mechanism.

General information

Depending on the action, the REST API performs 1 or 2 requests to the filterEndpoint endpoint specified in the tenant's configuration on the InCountry Portal.

It makes a request before submitting something to InCountry Vault (through the PoP API) and if the returned data contains some records, another request is made to check what part of this data can be returned to the user.

A response with an empty ids array indicates that the current user cannot perform the requested action against any of the records (0 records) from the requested list, and the user will receive a 403 Forbidden error without any further requests to the PoP API.

JSON schema of a request body to the filterEndpoint endpoint

{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"operation": {
"enum": [
"write-record",
"read-record",
"find-records",
"delete-record",
"aggregate-records",
"add-attachment",
"get-attachment",
"delete-attachment"
]
},
"params": {
"type": "object",
"properties": {
"ids": {
"type": "array",
"items": [
{
"type": "string"
}
]
},
"keys": {
"type": "array",
"items": [
{
"type": "string"
}
]
},
"fields": {
"type": "array",
"items": [
{
"type": "string"
}
]
}
},
"required": []
}
},
"required": [
"operation",
"params"
]
}

JSON schema of a response body from the filterEndpoint endpoint

note

The endpoint you create on the application side should return the response body in the format specified below. Returning data in a format other than the one specified will result in an error.

{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"ids": {
"type": "array",
"items": [
{
"type": "string"
}
]
},
"keys": {
"type": "array",
"items": [
{
"type": "string"
}
]
},
"fields": {
"type": "array",
"items": [
{
"type": "string"
}
]
}
},
"required": [
"ids",
"keys",
"fields"
]
}

How the operation parameter and number of filterEndpoint calls correlate with operations

Some operations performed by the REST API require two requests to the filterEndpoint endpoint, and some operations require only one. The following table shows the correlation between the operation type and requests that should be performed against the filterEndpoint endpoint.

OperationfilterEndpoint request data before a call to PoP APIfilterEndpoint request data after a call to PoP API
Create / update a single record
{
"operation": "write-record",
"params": {...}
}
{ 
"operation": "read-record",
"params": {...}
}
Delete a single record
{ 
"operation": "delete-record",
"params": {...}
}
Find records
{ 
"operation": "find-records",
"params": {...}
}
{ 
"operation": "read-record",
"params": {...}
}
Create multiple records
{ 
"operation": "write-record",
"params": {...}
}
{ 
"operation": "read-record",
"params": {...}
}
Delete multiple records
{ 
"operation": "delete-record",
"params": {...}
}
Aggregate records
{ 
"operation": "aggregate-records",
"params": {...}
}
Add a single attachment
{ 
"operation": "add-attachment",
"params": {...}
}
Get a single attachment
{ 
"operation": "get-attachment",
"params": {...}
}
Delete a single attachment
{ 
"operation": "delete-attachment",
"params": {...}
}

How to use the filterEndpoint endpoint

Let's examine what you need to implement on your side to properly handle access control levels within your application with the filterEndpoint endpoint

For example, let's explore the request to find records.

The request looks like this:

POST /webapi/records/find

The whole flow should be as follows:

  1. The user makes a request to the REST API endpoint with the following payload: For example, we want to find records of people older than 40 years and having income less than $100,000.

    POST /webapi/records/find
    { "filter": { "range_key1": { "gte": 40 }, "range_key2": { "lte": 100000 }}
  2. The REST API makes a request to the filterEndpoint endpoint at the customer’s backend to find out the applicability of the filter to records. Here, the REST API passes the keys against which the user wants to look up records.

    POST client-backend.com/filter-endpoint-url
    {
    "operation": "find-records",
    "params": {
    "keys": ["range_key1", "range_key2"]
    }
    }
  3. The filterEndpoint endpoint returns the list of all records (the user can access) to the REST API, what fields should be used for search in InCountry Vault: Here, the REST API gets the response after the initial ACL check performed at the customer’s application backend. The response contains identifiers of records the user can view and the record’s keys against which the user can look up records (only by age, as the Income field was removed by the filterEndpoint endpoint). The current user has no access to the Income field.

    {
    "ids": ["record_1", "record_2", "record_3", "record_4", "record_5"],
    "keys": ["range_key1"],
    "fields": []
    }
  4. The REST API examines the allowed keys and fields available to the user who performed the request. The ids array returned by the filterEndpoint endpoint will also be added to the find request anyway. The REST API performs a find request to InCountry Vault (through the PoP API) and InCountry Vault returns the found records within the scope of the user who requested them. Considering that the ACL check has forbidden the search against the Income field, the REST API can look up records by the Age field only.

    {
    "records": [
    {
    "record_key": "record_1",
    "parent_key": null,
    "body": { "ssn": "123-45-1234", "address": "Main street, 1" },
    "precommit_body": null,
    "version": 0,
    "is_encrypted": true,
    "created_at": "2023-09-02T13:07:01Z",
    "updated_at": "2023-09-02T13:07:01Z",
    "expires_at": null,
    "profile_key": null,
    "attachments": [],
    "range_key1": 60,
    ...
    "range_key10": null,
    "service_key1": null,
    ...
    "service_key5": null,
    "key1": "John",
    "key2": "Smith",
    "key3": null,
    ...
    "key25": null,
    "decimal_key1": null,
    ...
    "decimal_key20": null
    },
    {
    "record_key": "record_2",
    "parent_key": null,
    "body": { "ssn": "123-45-6789", "address": "Other street, 1" },
    "precommit_body": null,
    "version": 0,
    "is_encrypted": true,
    "created_at": "2023-09-01T13:07:01Z",
    "updated_at": "2023-09-01T13:07:01Z",
    "expires_at": null,
    "profile_key": null,
    "attachments": [],
    "range_key1": 45,
    ...
    "range_key10": null,
    "service_key1": null,
    ...
    "service_key5": null,
    "key1": "John",
    "key2": "Doe",
    "key3": null,
    ...
    "key25": null,
    "decimal_key1": null,
    ...
    "decimal_key20": null
    },
    {
    "record_key": "record_3",
    "parent_key": null,
    "body": { "ssn": "123-45-9876", "address": "2nd turn street, 1" },
    "precommit_body": null,
    "version": 0,
    "is_encrypted": true,
    "created_at": "2023-09-02T13:07:01Z",
    "updated_at": "2023-09-02T13:07:01Z"
    "expires_at": null,
    "profile_key": null,
    "attachments": [],
    "range_key1": 52,
    ...
    "range_key10": null,
    "service_key1": null,
    ...
    "service_key5": null,
    "key1": "Jane",
    "key2": "Doe",
    "key3": null,
    ...
    "key25": null,
    "decimal_key1": null,
    ...
    "decimal_key20": null
    }
    ]
    }
  5. The REST API performs another request to the filterEndpoint endpoint. For example, the REST API queries all the available record’s keys, including the ssn field (Social Security Number) and address field stored within the record's body key.

    POST client-backend.com/filter-endpoint-url
    {
    "operation": "read-record",
    "params": {
    "ids": ["record_2", "record_3", "record_4"],
    "keys": [
    "record_key",
    "parent_key",
    "body",
    "precommit_body",
    "version",
    "is_encrypted",
    "created_at",
    "updated_at",
    "expires_at",
    "profile_key",
    "attachments",
    "range_key1",
    ...
    "range_key10",
    "service_key1",
    ...
    "service_key5",
    "key1",
    ...
    "key25",
    "decimal_key1",
    ...
    "decimal_key20"
    ],
    "fields": ["ssn", "address"]
    }
    }
  6. The filterEndpoint endpoint returns the array of record ids, keys, and fields (from the body key) the user can view to the REST API: In our example, the user can view two records from the initial subset (returned at step 3). For each record, the user can view the following: - record identifier (record_key) - age (range_key1) - date when the record was updated (updated_at) - first name (key1) - last name (key2) - social security number (ssn) field (from the body key). The initial subset of records is further restricted to two records (instead of five).

    {
    "ids": ["record_2", "record_3"],
    "keys": ["record_key", "body", "range_key1", "updated_at", "key1", "key2"],
    "fields": ["ssn"]
    }
  7. The REST API returns the following response to the user. The response contains the record’s keys the user can view and the ssn field (Social Security Number) from the body key.

    {
    "data": [
    {
    "record_key": "record_2",
    "body": { "ssn": "123-45-6789" },
    "range_key1": 45,
    "updated_at": "2023-09-01T13:07:01Z",
    "key1": "John",
    "key2": "Doe"
    },
    {
    "record_key": "record_3",
    "body": { "ssn": "123-45-9876" },
    "range_key1": 52,
    "updated_at": "2023-09-02T13:07:01Z"
    "key1": "Jane",
    "key2": "Doe"
    }
    ],
    "meta": { "total": 100 },
    "errors": ["Error while applying ACL"]
    }
info

The REST API performs steps 2-6 in the background.

Using frontend-initiated requests

You can use the following requests:

Creating a single record

POST /webapi/records

Alternatively, this request can be used to update the record. Be careful, as it rewrites the data record with new values you provide.

ParameterTypeValueDescription
Authorizationstring (header)hKpKupTM391fd9sf9sd4646sf4dpE10xfQiorMxXarRKAHRhTfH_An OAuth token obtained from the authorization endpoint with the audience equal to the REST API address (URL). Please see the Authentication and authorization section.
x-client-authstring (header)hKpKupTM391pE10xfQiorMxXarRKAHRhTfH_A token from the application backend.
useAliasesquery?useAliases=trueAppend this string to the request address to use key-alias mappings instead of actual record’s keys.
Warning Don’t append anything to use the actual record’s keys.

Request body

Please see the example of the request body structure.

Example

{
"record_key": "string",
"body": "string",
"precommit_body": "string",
"profile_key": "string",
"parent_key": "string",
"range_key1": 0,
"range_key2": 0,
"range_key3": 0,
"range_key4": 0,
"range_key5": 0,
"range_key6": 0,
"range_key7": 0,
"range_key8": 0,
"range_key9": 0,
"range_key10": 0,
"service_key1": "string",
"service_key2": "string",
"service_key3": "string",
"service_key4": "string",
"service_key5": "string",
"key1": "string",
"key2": "string",
"key3": "string",
"key4": "string",
"key5": "string",
"key6": "string",
"key7": "string",
"key8": "string",
"key9": "string",
"key10": "string",
"key11": "string",
"key12": "string",
"key13": "string",
"key14": "string",
"key15": "string",
"key16": "string",
"key17": "string",
"key18": "string",
"key19": "string",
"key20": "string",
"key21": "string",
"key22": "string",
"key23": "string",
"key24": "string",
"key25": "string",
"expires_at": "2023-08-24T12:46:51.194Z",
"country": "string"
}

note

The country code is defined by the REST API instance. For one instance, you can use only one country code. For example, for https://se-restapi-mt-01.incountry.io it can only be se.

cURL request

curl --request POST \
--url 'https://{restApiURLAddress}/webapi/records' \
--header 'Authorization: Bearer {ACCESS_TOKEN}' \
--header 'x-client-auth: {APPLICATION_TOKEN}' \
--header 'Content-Type: application/json' \
--data '{
"record_key": "d1c2e12cfeababc8b95daf6902e210b1",
"profile_key": "4274e510a2f41aeb9e8e0f8b56ff6c2",
"range_key": 2000,
"key10": "New",
"key9": null,
"key8": null,
"key7": null,
"key6": null,
"key5": null,
"key4": "Shipping",
"key3": null,
"key2": null,
"key1": "Additional info",
"key": null,
"body": "{\"name\":\"John\",\"vehicle\":\"Audi\"}",
"country": "se"
}'

Responses

STATUS 201 - application/json The record has been created successfully. InCountry DRaaS will return the record data with information similar to the data you submitted within the request.

Example

{
"country": "se",
"key": "d1c2e12cfeababc8b95daf6902e210b1",
"record_key": "d1c2e12cfeababc8b95daf6902e210b1",
"profile_key": "4274e510a2f41aeb9e8e0f8b56ff6c2",
"range_key": 2000,
"range_key1": 2000,
"body": "{\"name\":\"John\",\"vehicle\":\"Audi\"}",
"key1": "Additional info",
"key2": null,
"key3": null,
"key4": "Shipping",
"key5": null,
"key6": null,
"key7": null,
"key8": null,
"key9": null,
"key10": "New"
}

STATUS 400 - application/json An invalid record has been provided.

STATUS 401 - Access is denied.

STATUS 409 - InCountry Vault for the country is not supported.

STATUS 415 - An unsupported request content type.

STATUS 422 - Validation of input parameters has failed.

STATUS 429 - The number of allowed requests has been exceeded.

STATUS 5** - Server error.

Deleting a record

DELETE /webapi/records/{record_key}

Request parameters

ParametersTypeValueDescription
Authorizationstring (header)hKpKupTM391fd9sf9sd4646sf4dpE10xfQiorMxXarRKAHRhTfH_An OAuth token obtained from the authorization endpoint with the audience equal to the REST API address (URL). Please see the Authentication and authorization section.
x-client-authstring (header)hKpKupTM391pE10xfQiorMxXarRKAHRhTfH_A token from the application backend.
record_keystring/arrayk1234Unique primary key (record_key) for record identification
cURL request

curl --request DELETE \
--url 'https://{restApiURLAddress}/webapi/records/{record_key}' \
--header 'Authorization: Bearer {ACCESS_TOKEN}' \
--header 'x-client-auth: {APPLICATION_TOKEN}' \

//URL EXAMPLE
https://se-restapi-mt-01.incountry.io/webapi/records/d1c2e12cfeababc8b95daf6902e210b1

Responses

STATUS 204 - The record has been successfully deleted.

STATUS 401- Access is denied.

STATUS 404 - The record has not been found.

STATUS 422 - Validation of input parameters has failed.

STATUS 429 - The number of allowed requests has been exceeded.

STATUS 5** - Server error.

Searching for records

POST /webapi/records/find

Request parameters

ParametersTypeValueDescription
Authorizationstring (header)hKpKupTM391fd9sf9sd4646sf4dpE10xfQiorMxXarRKAHRhTfH_An OAuth token obtained from the authorization endpoint with the audience equal to the REST API address (URL). Please see the Authentication and authorization section.
x-client-authstring (header)hKpKupTM391pE10xfQiorMxXarRKAHRhTfH_A token from the application backend.
record_keystring/arrayk1234Unique primary key (record_key) for record identification

Request body

ParametersTypeExampleDescription
countryISO country code (lowercase)sg (equals to Singapore)Country where a new record is looked up. You can use different countries.
filterobjectSee the example.Specify the criteria for filtration within the filter object.You can look up records by any of record fields. For the full list of supported fields, please see the Available record fields section.
optionsobjectSee the example.Specify the criteria for returning the search results:* limit,offset,sort
limitinteger10Sets the maximal number of search results. It is passed as a part of the options object.
offsetinteger50Specifies the offset (pagination) of records from which the record lookup is performed. It is passed as a part of the options object.
sortarraySpecifies the sorting order of records against a specific field. The sorting can be performed by the following fields:range_keyN, created_at, updated_at, expires_at, keyN. The order in which you specify fields within the sort array will affect the sorting order of records.It is passed as a part of the options object.

Please see the example of the request structure.

Example

{
"country": "string",
"filter": {
"key": "string",
"record_key": "string",
"profile_key": "string",
"range_key": 0,
"range_key1": 0,
"range_key2": 0,
"range_key3": 0,
"range_key4": 0,
"range_key5": 0,
"range_key6": 0,
"range_key7": 0,
"range_key8": 0,
"range_key9": 0,
"range_key10": 0,
"key1": "string",
"key2": "string",
"key3": "string",
"key4": "string",
"key5": "string",
"key6": "string",
"key7": "string",
"key8": "string",
"key9": "string",
"key10": "string",
"key11": "string",
"key12": "string",
"key13": "string",
"key14": "string",
"key15": "string",
"key16": "string",
"key17": "string",
"key18": "string",
"key19": "string",
"key20": "string",
"service_key1": "string",
"service_key2": "string",
"service_key3": "string",
"service_key4": "string",
"service_key5": "string",
"version": 0,
"search_keys": "string"
},
"options": {
"limit": 0,
"offset": 0,
"sort": [
{
"range_key1": "asc"
},
{
"range_key2": "asc"
},
{
"range_key3": "asc"
},
{
"range_key4": "asc"
},
{
"range_key5": "asc"
},
{
"range_key6": "asc"
},
{
"range_key7": "asc"
},
{
"range_key8": "asc"
},
{
"range_key9": "asc"
},
{
"range_key10": "asc"
},
{
"created_at": "asc"
},
{
"updated_at": "asc"
},
{
"expires_at": "asc"
},
{
"key1": "asc"
},
{
"key2": "asc"
},
{
"key3": "asc"
},
{
"key4": "asc"
},
{
"key5": "asc"
},
{
"key6": "asc"
},
{
"key7": "asc"
},
{
"key8": "asc"
},
{
"key9": "asc"
},
{
"key10": "asc"
},
{
"key11": "asc"
},
{
"key12": "asc"
},
{
"key13": "asc"
},
{
"key14": "asc"
},
{
"key15": "asc"
},
{
"key16": "asc"
},
{
"key17": "asc"
},
{
"key18": "asc"
},
{
"key19": "asc"
},
{
"key20": "asc"
}
]
}
}

Example

{
  "country": "sg",
  "filter": {
    "key1": ["k1234", "k1235"],
    "key2": ["John", "Jane"]
  },
"options": {
"limit": 10,
"offset": 50
}
}

or

{
"country": "sg",
"filter": {
"search_keys": "abc"
}
}

or

{
"country": "sg",
"filter": {
"search_keys": "abc",
"range_key1": [1, 2]
}
}

cURL request

//FINDS A RECORD BY THE SPECIFIED CRITERIA

curl --request POST \
--url 'https://{restApiURLAddress}/webapi/records/find' \
--header 'Authorization: Bearer {ACCESS_TOKEN}' \
--header 'x-client-auth: {APPLICATION_TOKEN}' \
--header 'Content-Type: application/json' \
--data '{
"country": "se",
"filter": {
"range_key": 3000,
"key4": "Shipping",
"profile_key": "baab015f2f9c350ab610fddd3986c53",
"record_key": "69f6a71405facac91d002dc9adce85fa"
},
"options": {
"limit": 10,
"offset": 0
}
}'

//FINDS RECORDS THAT HAVE THE range_key FIELD WITHIN =} 1000 AND {= 4000 RANGE

curl --request POST \
--url 'https://{restApiURLAddress}/webapi/records/find' \
--header 'Authorization: Bearer {ACCESS_TOKEN}' \
--header 'Content-Type: application/json' \
--header 'x-client-auth: {APPLICATION_TOKEN}' \
--data '{
"country": "se",
"filter": {
"range_key": {"$gte":1000, "$lte":4000},
"key4": "Shipping",
"profile_key": "baab015f2f9c350ab610fddd3986c53",
"record_key": "69f6a71405facac91d002dc9adce85fa"
},
"options": {
"limit": 10,
"offset": 0
}
}'

//FINDS RECORDS WHOSE THE range_key FIELD TAKES ONE OF THE SPECIFIED VALUES

curl --request POST \
--url 'https://{restApiURLAddress}/webapi/records/find' \
--header 'Authorization: Bearer {ACCESS_TOKEN}' \
--header 'x-client-auth: {APPLICATION_TOKEN}' \
--header 'Content-Type: application/json' \
--data '{
"country": "se",
"filter": {
"range_key": [1000, 4000],
"key4": "Shipping",
"profile_key": "baab015f2f9c350ab610fddd3986c53",
"record_key": "69f6a71405facac91d002dc9adce85fa"
},
"options": {
"limit": 10,
"offset": 0
}
}'

//FINDS RECORDS AND SORTS THEM BY FIELD IN ASCENDING/DESCENDING ORDER

curl --request POST \
--url 'https://{restApiURLAddress}/api/records/find' \
--header 'Authorization: Bearer {ACCESS_TOKEN}' \
--header 'Content-Type: application/json' \
--data '{
"country": "se",
"filter": {
"range_key": [1000, 4000],
"key4": "Shipping",
"profile_key": "baab015f2f9c350ab610fddd3986c53",
"record_key": "69f6a71405facac91d002dc9adce85fa"
},
"options": {
"limit": 10,
"offset": 0,
"sort":[{"key1":"asc"}, {"key2": "desc"}]
}
}'

Responses

STATUS 200 - application/json Returns information about the found record or records. This status is also returned when no records matching the search criteria are found.

Example

{
"data": [
{
"country": "se",
"key": "69f6a71405facac91d002dc9adce85fa",
"record_key": "69f6a71405facac91d002dc9adce85fa",
"parent_key": null,
"profile_key": "baab015f2f9c350ab610fddd3986c53",
"range_key": 3000,
"range_key1": 3000,
"range_key2": null,
"range_key3": null,
"range_key4": null,
"range_key5": null,
"range_key6": null,
"range_key7": null,
"range_key8": null,
"range_key9": null,
"range_key10": null,
"body": "{\"name\":\"Alice\",\"vehicle\":\"Mercedes\"}",
"precommit_body": null,
"key1": "Additional info",
"key2": null,
"key3": null,
"key4": "Shipping",
"key5": null,
"key6": null,
"key7": null,
"key8": null,
"key9": null,
"key10": "New",
"key11": null,
"key12": null,
"key13": null,
"key14": null,
"key15": null,
"key16": null,
"key17": null,
"key18": null,
"key19": null,
"key20": null,
"service_key1": null,
"service_key2": null,
"attachments": [],
"created_at": "2021-03-26T11:57:45.000Z",
"updated_at": "2021-03-26T11:57:45.000Z",
"version": 0
}
],
"meta": {
"count": 1,
"limit": 10,
"offset": 0,
"total": 1
}
} "updated_at": "2020-11-21T12:05:28.000Z"
}
],
"meta": {
"count": 2,
"limit": 100,
"offset": 0,
"total": 2
}
}

STATUS 401 - Access is denied.

STATUS 403 - Partial-text match is not enabled in the requested country.

STATUS 409 - InCountry Vault is not enabled in the requested country.

STATUS 409 - An unsupported request content type.

STATUS 415 - Validation of input parameters has failed.

STATUS 422 - Validation of input parameters has failed.

STATUS 429 - The number of allowed requests has been exceeded.

STATUS 5** - Server error.

Aggregating records

POST /webapi/records/aggregate

ParameterTypeValueDescription
Authorizationstring (header)hKpKupTM391fd9sf9sd4646sf4dpE10xfQiorMxXarRKAHRhTfH_An OAuth token obtained from the authorization endpoint with the audience equal to the REST API address (URL). Please see the Authentication and authorization section.
x-client-authstring (header)hKpKupTM391pE10xfQiorMxXarRKAHRhTfH_A token from the application backend.
useAliasesquery?useAliases=trueAppend this string to the request address to use key-alias mappings instead of actual record’s keys.
Warning Don’t append anything to use the actual record’s keys.

Please see the example of the request structure.

Example

{
"next": "string",
"metrics": {
"additionalProp1": {
"func": "sum",
"key": "string"
},
"additionalProp2": {
"func": "sum",
"key": "string"
},
"additionalProp3": {
"func": "sum",
"key": "string"
}
},
"filter": {
"record_key": "string",
"profile_key": "string",
"parent_key": "string",
"range_key1": 0,
"range_key2": 0,
"range_key3": 0,
"range_key4": 0,
"range_key5": 0,
"decimal_key1": 0,
"decimal_key2": 0,
"decimal_key3": 0,
"decimal_key4": 0,
"decimal_key5": 0,
"key1": "string",
"key2": "string",
"key3": "string",
"key4": "string",
"key5": "string",
"key6": "string",
"key7": "string",
"key8": "string",
"key9": "string",
"key10": "string",
"key11": "string",
"key12": "string",
"key13": "string",
"key14": "string",
"key15": "string",
"key16": "string",
"key17": "string",
"key18": "string",
"key19": "string",
"key20": "string",
"key21": "string",
"key22": "string",
"key23": "string",
"key24": "string",
"key25": "string",
"service_key1": "string",
"service_key2": "string",
"service_key3": "string",
"service_key4": "string",
"service_key5": "string",
"version": 0,
"search_keys": "string",
"created_at": "2023-08-04T14:48:38.147Z",
"updated_at": "2023-08-04T14:48:38.147Z"
},
"group_by": {
"limit": 0,
"keys": [
"string"
]
}
}

Within the metrics section, you can define the aggregation parameters:

ArgumentDescription
additionalPropNYou can declare the aggregated metric, for example, total_sales_amount, record_count, or total_revenue.
funcYou can define the aggregation function to apply:count - cannot take additional arguments. Counts the number of records.sum - can take additional arguments. Summarizes values against a specific record’s key. You need to pass additional argument for summarization:* key - the record’s key name which values should be summarized. Only numeric fields (range_keyN) can be summarized.
nextYou can use the pagination when the number of groups within the returned aggregation exceeds 100 groups. In this case, the REST API will return the next value in the first response. You need to use this value to query the next batch of groups and update this value with the value from the prior response every time you query a subsequent batch of groups.
cURL request

curl --request POST \
--url 'https://{restApiURLAddress}/webapi/records/aggregate' \
--header 'Authorization: Bearer {ACCESS_TOKEN}' \
--header 'x-client-auth: {APPLICATION_TOKEN}' \
--header 'Content-Type: application/json' \
--data '{
"metrics": {
"total_revenue": {
"func": "sum",
"key": "range_key3"
},
"total_tax": {
"func": "sum",
"key": "range_key4"
},
"transaction_count": {
"func": "count"
}
},
"filter": {
"range_key2": {"$gte":1000, "$lte":4000},
"key4": "Order with Shipping"
},
"options": {
"limit": 100,
"offset": 0
}
}'

//URL EXAMPLE
https://se-restapi-mt-01.incountry.io/webapi/records/aggregate

When you query the next batch of groups within the aggregation, you can pass only the next value within the request:

curl --request POST \
--url 'https://{restApiURLAddress}/api/records/aggregate' \
--header 'Authorization: Bearer {ACCESS_TOKEN}' \
--header 'x-client-auth: {APPLICATION_TOKEN}' \
--header 'Content-Type: application/json' \
--data '{
"next": "ZGluZyBkb25nIGNoaW5nIGNob25n",
}'

//URL EXAMPLE
https://se-restapi-mt-01.incountry.io/api/records/aggregate

Responses

STATUS 200 - JSON This response returns the results of aggregation and summarization.

Example