InCountry logo
mobile-nav
Search
  • Products
    • Platform
      • Overview
      • Compliance and security
      • How it works
      • For SaaS
      • For internal apps
    • Gateways
      • Email
      • HTML
      • Payments
      • Web Forms
  • Solutions
    • Energy
    • Financial services
    • Healthcare
    • Retail
    • Technology
  • Integrations
    • SaaS
      • Cegid
      • Intertrust
      • Mambu
      • PayPal
      • Salesforce
      • Segment
      • ServiceNow
      • Stripe
      • Twilio
      • Veeva Systems
    • IAAS
      • InCountry on Alibaba Cloud
      • InCountry on Yandex.Cloud
  • Resources
    • Country compliance
    • Documentation
    • Library
    • Partners
    • Pricing
  • About
    • Blog
    • Careers
    • Contact Us
    • FAQ
    • Leadership
  • Login
  • Schedule a Demo

›Serverless

Home
  • InCountry Platform
Portal
  • Getting started
  • Documentation
    • Dashboard
    • Managing environments
    • Managing clients and integrations
    • Managing Border configuration
    • Managing payment vaults
    • Managing email gateways
    • Managing serverless scripts
    • Managing file imports
    • Managing profile and organization
    • Managing users
    • Managing secret keys
    • Managing recommendation modules
    • Managing subscription
  • Release notes
Border
  • Documentation
  • Release notes
REST API
  • Documentation
  • How to test CRUD requests through REST API
  • Release notes
Serverless
  • Documentation
Salesforce
  • About
  • Overview
  • Quick start guide for three-model package
  • Quick start guide for legacy package
  • Administrator's guide
    • Managing the package
    • Managing permissions
    • Managing OAuth2 authentication and authorization
    • Managing certificates
    • Registering CSP Trusted Sites
    • Managing InCountry Endpoints
    • Managing REST endpoints
    • Managing InCountry flags
    • Loading the application
    • Managing data regulation policies
    • Managing protected fields
    • Hashing the UserName field
    • Managing custom objects
    • Replacing standard elements
    • Configuring record search
    • Managing components
    • Setting up Salesforce Experience Cloud
    • Managing serverless functions
    • Managing InCountry cache
    • Managing Apex triggers
    • Managing record synchronization
    • Using Email-to-Case feature
    • Debugging
    • Migrating data from one Salesforce organization to another
  • Developer’s guide
    • Apex SDK
    • JavaScript API
    • Retrieving record statistics
    • Tracking field history
  • User's guide
    • Working with protected fields
    • Sending compliant email messages
    • Importing data into Salesforce
    • Migrating records
    • Managing audit reports
    • Converting leads
    • Managing reports
    • FAQ
    • Release notes
Payment Vault
  • Documentation
BYOK
  • Documentation
FAQ
  • Get started with the platform
  • Integration options
  • Data regulation models
  • Limits and quotas
  • Video tutorials
Service Status
  • Status

InCountry Serverless Documentation

About

Serverless is a part of the InCountry Platform. It lets you execute serverless scripts on protected data so that it does not leave the originating country. All the calculations, aggregation, and validations are performed within this country and do not reach your application server, located in another country. This way, you do not violate the local regulations and keep compliance with all data protection and localization laws of the data originating country.

Get started with Serverless

The Serverless component of the InCountry Platform allows you to execute serverless scripts on regulated data in the originating country.

Serverless Diagram

Management of serverless scripts is available on the InCountry Portal. If you need to automate the management and execution of serverless scripts, you can use REST API.

To get started with Serverless, please follow these steps:

  1. Sign up at InCountry Portal.

  2. Create an environment for the country where you want to execute serverless scripts.

  3. Create an integration of the Serverless type.

  4. Use the certificate and private key to manage serverless scripts with REST API.

  5. Execute serverless scripts remotely.

Authorization of requests to REST API

Authentication and authorization of requests to REST API are performed with a certificate and a private key.

It would be best if you created a new integration of the Serverless type on the InCountry Portal. Upon creation, InCountry Portal will prompt you to download a certificate and a private key restricted to a specific REST API endpoint in some countries.

Once you get your certificate and private key, you can use them to authorize data requests to REST API.

Within each request, you need to specify the paths to the certificate and the private key. Without doing this, all your requests will be unauthorized and rejected by REST API.

In examples of cURL requests, you can see the following request parameters:

  --cert ./{certificateName}.pem \
  --key ./{keyName}.key \

Within these parameters you need to replace the {certificateName} and {keyName} strings with their actual names.

While performing requests to a specific country, please ensure that you have specified the correct country code within the request and you are using the certificate and private key which attribute to this country.

Management of serverless scripts

Please check documentation for REST API before proceeding to this section.

Management of serverless scripts allows you to create additional record validation and data calculation mechanisms for protected data stored in countries that impose enforced data regulation.

You can manage serverless scripts within the InCountry Platform as follows:

  • publish serverless scripts

  • execute serverless scripts

  • get the list of serverless scripts

  • get a specific serverless script

  • delete the no longer needed serverless scripts

Publishing a serverless script

POST ​/serverless/publish

  • Request parameters
ParametersTypeDescription
scriptNamestringName of a serverless script that is published.
scriptBodystringBody of the serverless script.
optionsobjectA JSON object with the country and forceUpdate parameters.
countrystringA country to which a server script is published to.
forceUpdatebooleanA flag that the serverless script must be forcedly updated.
  • cURL request
curl --request POST \
  --url https://{restApiURLAddress}/serverless/publish \
  --header 'Content-Type: application/json' \
  --cert ./{certificateName}.pem \
  --key ./{keyName}.key \
  --data '{
    "scriptName": "{SCRIPT-NAME}",
    "scriptBody": "module.exports.handler = async (storage, country, params, modules) => { const recordData = { recordKey: '\''UniqRecordKey'\'', body: params.bodyParam, }; console.log(recordData); const writeResponse = await storage.write(country, recordData); return { result: '\''ok'\'' }; };",
    "options": {
        "country": "se",
        "forceUpdate": false
    }
}'
  • Responses

STATUS 201 - plain This response is returned when the serverless script has been successfully published.

{"scriptName":"{SCRIPT-NAME}","scriptBody":"module.exports.handler = async (storage, country, params, modules) => { const recordData = { recordKey: 'UniqRecordKey', body: params.bodyParam, }; console.log(recordData); const writeResponse = await storage.write(country, recordData); console.log(writeResponse); return { result: 'ok' }; };"}

STATUS 401 - This response is returned when the request is unauthorized.

STATUS 409 - This response is returned when the serverless script with the current name already exists.

STATUS 5** - Server error.

Executing a serverless script

The endpoint executes the published serverless script synchronously and returns its output and meta information.

POST ​/serverless/execute

  • Request parameters
ParametersTypeDescription
scriptNamestringName of a serverless script that is executed.
optionsobjectObject with the country parameter.
countrystringA country in which a server script is executed against.
  • cURL request
curl --request POST \
  --url https://{restApiURLAddress}/serverless/execute \
  --header 'Content-Type: application/json' \
  --cert ./{certificateName}.pem \
  --key ./{keyName}.key \
  --data '{
    "scriptName": "{SCRIPT-NAME}",
    "options": {
        "country": "se"
    },
    "scriptParams": {
        "bodyParam": "test"
    }
}'
  • Responses

STATUS 201 - plain This response is returned when the serverless script has been successfully executed.

{"result":{"result":"ok"},"duration":1381,"error":null}

STATUS 400 - This response is returned when the request is incorrect.

{"result":null,"duration":775,"error":"InputValidationError: delete() Validation Error: <RecordKey> should be RecordKey but got {\"recordKey\":\"UniqRecordKey\",\"body\":\"test\"}: Record key must be a non-empty string"}

STATUS 401 - This response is returned when the request is unauthorized.

STATUS 404 - This response is returned when the serverless script has not been found.

STATUS 5** - Server error.

Getting a list of serverless scripts

The endpoint returns a list of published serverless scripts. It supports pagination and does not return bodies of serverless scripts.

GET /serverless/scripts

  • Request parameters
ParametersTypeDescription
offsetobjectSome items to skip before returning a list of serverless scripts.
limitstringThe maximal number of serverless scripts to return. The maximal number is limited to 100.
  • cURL request
curl --request GET \
  --url "https://{restApiURLAddress}/serverless/functions?limit=10&offset=0" \
  --cert ./{certificateName}.pem \
  --key ./{keyName}.key
  • Responses

STATUS 201 - plain This response returns a list of serverless scripts.

{"data":[{"script_name":"{SCRIPT-NAME}","created_at":"2021-03-30T12:50:45.000Z","updated_at":"2021-03-30T12:59:47.000Z"},{"script_name":"e2e-script-1-53203","created_at":"2021-03-26T10:13:30.000Z","updated_at":"2021-03-26T10:13:30.000Z"},{"script_name":"e2e-script-66046","created_at":"2021-03-26T10:13:29.000Z","updated_at":"2021-03-26T10:13:29.000Z"},{"script_name":"e2e-script-1-30449","created_at":"2021-03-26T09:02:30.000Z","updated_at":"2021-03-26T09:02:30.000Z"},{"script_name":"e2e-script-26244","created_at":"2021-03-26T09:02:29.000Z","updated_at":"2021-03-26T09:02:29.000Z"}],"meta":{"count":5,"limit":10,"offset":0,"total":5}}

STATUS 400 - This response is returned when specified parameters are incorrect.

STATUS 401 - This response is returned when the request is unauthorized.

STATUS 5** - Server error.

Getting a serverless script

The endpoint returns information about a specific serverless script.

GET ​/serverless/scripts/{scriptName}

  • Request parameters
ParametersTypeDescription
scriptNamestringName of a serverless script which information should be returned.
  • cURL request
curl --request GET \
  --url https://{restApiURLAddress}/serverless/functions/{SCRIPT-NAME} \
  --cert ./{certificateName}.pem \
  --key ./{keyName}.key
  • Responses

STATUS 201 - plain This response returns a serverless script with its information.

{"script_name":"{SCRIPT-NAME}","script_body":"module.exports.handler = async (storage, country, params, modules) => { const recordData = { recordKey: 'UniqRecordKey', body: params.bodyParam, }; console.log(recordData); const writeResponse = await storage.write(country, recordData); return { result: 'ok' }; };","created_at":"2021-03-30T12:50:45.000Z","updated_at":"2021-03-30T12:59:47.000Z"}%

STATUS 401 - This response is returned when the request is unauthorized.

STATUS 404 - This response is returned when the specified serverless script has not been found.

STATUS 5** - Server error.

Deleting a serverless script

The endpoint deletes a specifiс serverless script.

DELETE ​/serverless​/scripts​/{scriptName}

  • Request parameters
ParametersTypeDescription
scriptNamestringName of a serverless script that should be deleted.
  • cURL request
curl --request DELETE \
  --url https://{restApiURLAddress}/serverless/functions/{SCRIPT-NAME} \
  --cert ./{certificateName}.pem \
  --key ./{keyName}.key
  • Responses

STATUS 204 - plain This response is returned when the serverless script has been successfully deleted.

STATUS 401 - This response is returned when the request is unauthorized.

STATUS 404 - This response is returned when the specified serverless script has not been found.

STATUS 5** - Server error.

Serverless script examples

All serverless scripts should be written as a JavaScript function.

Below you can find an example of the serverless script.

In the current examples, storage is an instance of the Storage class. Please check our Node.js SDK documentation on how to use it properly.

Example #1 - Checking the existence of the record with a specific email

module.exports.handler = async (storage, country, params, modules) => {
  const result = await storage.find(country, { key1: params.email });
  if (result.records.length > 0) {
    return true;
  }
  return false;
};

Example #2 - Showing how to use all the methods in a junction

module.exports.handler = async (storage, country, params, modules) => {
  let result;
  const validateRecord = (expectedRecord, actualRecord, methodValue) => { // method to compare actual record with expected
    if (expectedRecord.recordKey !== actualRecord.recordKey) {
      return `bad recordKey ${methodValue}`;
    }
    if (expectedRecord.body !== actualRecord.body) {
      return `bad body ${methodValue}`;
    }
    if (expectedRecord.key1 !== actualRecord.key1) {
      return `bad key1 ${methodValue}`;
    }
    if (expectedRecord.key2 !== actualRecord.key2) {
      return `bad key2 ${methodValue}`;
    }
    if (expectedRecord.key3 !== actualRecord.key3) {
      return `bad key3 ${methodValue}`;
    }
    if (expectedRecord.key10 !== actualRecord.key10) {
      return `bad key10 ${methodValue}`;
    }
    if (expectedRecord.profileKey !== actualRecord.profileKey) {
      return `bad profileKey ${methodValue}`;
    }
    if (expectedRecord.serviceKey1 !== actualRecord.serviceKey1) {
      return `bad serviceKey1 ${methodValue}`;
    }
    if (expectedRecord.rangeKey1 !== actualRecord.rangeKey1) {
      return `bad rangeKey1 ${methodValue}`;
    }
    if (expectedRecord.rangeKey10 !== actualRecord.rangeKey10) {
      return `bad rangeKey10 ${methodValue}`;
    }
    return 'ok';
  };
  const validateMeta = (expectedCount, expectedTotal, expectedOffset, expectedLimit, actualMeta, methodValue) => { // method to compare actual metadata with expected
    if (expectedCount !== actualMeta.count) {
      return `bad count ${methodValue}`;
    }
    if (expectedTotal !== actualMeta.total) {
      return `bad total ${methodValue}`;
    }
    if (expectedOffset !== actualMeta.offset) {
      return `bad offset ${methodValue}`;
    }
    if (expectedLimit !== actualMeta.limit) {
      return `bad limit ${methodValue}`;
    }
    return 'ok';
  };
  const recordData = {
    recordKey: params.recordKeyParam,
    body: params.bodyParam,
    key1: params.key1Param,
    key2: params.key2Param,
    key3: params.key3Param,
    key10: params.key10Param,
    profileKey: params.profileKeyParam,
    serviceKey1: params.serviceKey1Param,
    rangeKey1: params.rangeKey1Param,
    rangeKey10: params.rangeKey10Param,
  };
  const writeResult = await storage.write(country, recordData);
  const readRecord = await storage.read(country, params.recordKeyParam);
  result = validateRecord(recordData, readRecord.record, 'read'); // compares if the written record matches the read one
  if (result !== 'ok') {
    return result;
  }
  const findOneRecord = await storage.findOne(country, { recordKey: params.recordKeyParam });
  result = validateRecord(recordData, findOneRecord.record, 'findOne by recordKey'); // compares if the written record matches the found one by the recordKey with the findOne method
  if (result !== 'ok') {
    return result;
  }
  const findOneRecord2 = await storage.findOne(country, { key2: params.key2Param });
  result = validateRecord(recordData, findOneRecord2.record, 'findOne by key2'); // compares if the written record matches the found one by the key2 with the findOne method
  if (result !== 'ok') {
    return result;
  }
  const limit = 10;
  const offset = 0;
  const findResponse = await storage.find(country, { recordKey: params.recordKeyParam }, { limit, offset });
  const actualMeta = findResponse.meta;
  result = validateMeta(1, 1, offset, limit, actualMeta, 'find by recordKey'); // compares if the written record meta matches the found record by the recordKey meta
  if (result !== 'ok') {
    return result;
  }
  const findRecord = findResponse.records[0];
  result = validateRecord(recordData, findRecord, 'find by recordKey'); // compares if the written record matches the found one by the recordKey with the find method
  if (result !== 'ok') {
    return result;
  }
  const findResponse2 = await storage.find(country, { rangeKey10: params.rangeKey10Param }, { limit, offset });
  const actualMeta2 = findResponse2.meta;
  result = validateMeta(1, 1, offset, limit, actualMeta2, 'find by rangeKey10'); // compares if the written record meta matches the found record by the rangeKey10 meta
  if (result !== 'ok') {
    return result;
  }
  const findRecord2 = findResponse2.records[0];
  result = validateRecord(recordData, findRecord2, 'find by rangeKey10'); // compares if the written record matches the found one by the rangeKey10 with the find method
  if (result !== 'ok') {
    return result;
  }
  await storage.delete(country, params.recordKeyParam); // delete record
  return result;
};
← Release notesAbout →
  • About
  • Get started with Serverless
  • Authorization of requests to REST API
  • Management of serverless scripts
    • Publishing a serverless script
    • Executing a serverless script
    • Getting a list of serverless scripts
    • Getting a serverless script
    • Deleting a serverless script
  • Serverless script examples
    • Example #1 - Checking the existence of the record with a specific email
    • Example #2 - Showing how to use all the methods in a junction
InCountry logo blue
© InCountry 2022.
All rights reserved. InCountry, Inc
  • PRIVACY POLICY
  • TERMS OF SERVICE
  • Social share
    • YouTube logo
    • Facebook logo
    • Twitter logo
    • LinkedIn
  • Column 1
    • Products
      • Platform
        • Overview
        • Compliance and security
        • How it works
        • For SaaS
        • For internal apps
      • Gateways & Vaults
        • Email
        • HTML
        • Payments
        • Web Forms
    • Solutions
      • Energy
      • Financial services
      • Healthcare
      • Retail
      • Technology
  • Column 2
    • Integrations
      • SaaS
        • Cegid
        • Intertrust
        • Mambu
        • PayPal
        • Salesforce
        • Segment
        • ServiceNow
        • Stripe
        • Twilio
        • Veeva Systems
      • IAAS
        • InCountry on Alibaba Cloud
        • InCountry on Yandex.Cloud
  • Column 3
    • Resources
      • Country compliance
      • Documentation
      • Library
      • Partners
      • Pricing
    • About
      • Blog
      • Careers
      • Contact Us
      • FAQ
      • Leadership