Download OpenAPI specification:Download
MyInfo Business REST APIs for retrieving Entity and Person data.
Note - this specification is subject to changes based on evolution of the APIs.
0.2.5 (15 July 2019)
""1 - Individual2 - Local Company3 - Foreign Company4 - Unregistered Local Entity5 - Limited Liability Partnerships6 - Unregistered Foreign Entity0.2.4 (05 Dec 2018)
Base URL changes:
myinfosg.api.gov.sg to api.myinfo.gov.sgmyinfosgstg.api.gov.sg/test to test.api.myinfo.gov.sgmyinfosgstg.api.gov.sg/dev to sandbox.api.myinfo.gov.sgSecurity header (.e. no longer needed in basestring)
.e. is required in the domain name: e.g. myinfosgstg.api.gov.sg -> myinfosgstg.e.api.gov.sg.
api.myinfo.gov.sgData items deprecated:
New data items available:
Added link to MyInfo Business demo app under Support section for easy reference.
0.2.3 (19 November 2018)
Entity Type field to encompass more entity types.Company Type and Business Constitution to give further breakdown to Company and Business entity types.0.2.2 (9 November 2018)
/.0.2.1 (29 August 2018)
0.2.0 (3 August 2018)
Entity-Person-Sample with no authentication for sandbox testing.Entity-Person call such that Entity object is before Person object.0.1.1 (24 July 2018)
uen_uinfin0.1.0 (20 June 2018)
The RESTful API adopts Semantic Versioning 2.0.0 for releases, and every new release of the API increments the version numbers in the following format:
{MAJOR}.{MINOR}.{PATCH}{MAJOR} number introduces incompatible API changes with previous {MAJOR} number also resets {MINOR} to 0,{MINOR} number introduces new functionalities or information that are backward compatible also resets {PATCH} to 0, and{PATCH} number introduces bug fixes and remains backward compatible.Pre-release or draft versions, when provided, are denoted by appended hypen - with a series of separate identifiers {LABEL}-{VERSION} following the {PATCH} number. Such releases are unstable and may not provide the intended compatibility with the specification in draft status.
Serving as notice, the RESTful API in version 2.X.X are incompatible with version 1.X.X releases.
Despite backward compatibility in {MINOR} or {PATCH} releases, API consumers are best to evaluate and determine their implementation does not disrupt use-case requirements.
Nationality field, where the return value sometimes will be SP which refers to "Singapore Permanent Resident". This value will be moved to a separate "Residential Status" field in later releases.The following diagram illustrates how the integration with MyInfo Business APIs work:

As shown above, your application will be interfacing with our API Gateway to integrate successfully with MyInfo Business.
The RESTful API provides both testing and live environments accessible over the Internet via HTTPS.
Consumers are to ensure firewall clearance on their edge network nodes for connecting to the APIs.
The convention used by API endpoints' URL are in the following format:
https://{ENV_DOMAIN_NAME}/{CONTEXT}/{VERSION}/{RESOURCE}{ENV_DOMAIN_NAME} indicates MyInfo's API domain names - respectively:
sandbox.api.myinfo.gov.sg, ortest.api.myinfo.gov.sg, orapi.myinfo.gov.sg, following/{CONTEXT}, indicates the context of the API call = /biz
/{VERSION} indicates the endpoint's release {MAJOR} version number
path - for this release = /v2
/{RESOURCE} indicates the API resource path name.
Any additional query string parameters are appended as needed.
The sandbox environment is used for your testing when developing your prototype. The Entity-Person-Sample and Entity-Person API will return test data previously shared by our officer via email. For test data matters, please contact us.
sandbox.api.myinfo.gov.sgThe test enviroment is used for testing your application with the full security measures required in production. The Entity-Person API will return test data previously shared by our officer via email. For test data matters, please contact us.
test.api.myinfo.gov.sgThe production enviroment is the actual live environment with full security measures and live data.
api.myinfo.gov.sgThe following are the scheduled downtimes for the various environments:
MyInfo Business's API gateway supports accessing of APIs via the following interfaces:
HTTP version 1.1 connection over TLS (Transport Layer Security) version 1.1 or 1.2 standards, and ciphersuites:
Below is the list of recommended cipher suites that you may use:
IMPORTANT: ensure your server supports TLS 1.1 or 1.2 and supports a cipher suite in the list above.
Accessing the RESTful API using prior versions of TLS or unsupported ciphersuites will result in connectivity errors. MyInfo Business' API gateway does not support 2-way TLS client nor mutual authentication.
API HTTP interface features:
Content-Type header application/json, alsoContent-Length header is omitted by having Transfer-Encoding header chunked emitted for streaming data, andAccept-Encoding: gzip and indicated in Content-Encoding header gzip.MyInfo Business APIs use OAuth2.0 authorisation code flow to perform authentication & authorisation.
The sequence diagram below illustrates the steps involved in integrating your application with our APIs:

The flow consists of 3 APIs:
Authorise
Token
Protected Resource (Entity-Person)
Access to all server-to-server APIs will be authenticated by MyInfo Business' API gateway. Prior to consumption of API, respective consumers are required to have:
Authentication methods provided by MyInfo Business' API gateway on internet:
SHA256withRSA digital signature (see "Request Signing" section below)NOTE: Test and Production Environments only
All server-to-server API requests are to be digitally signed, by including the following parameters and values in the Authorization header:
Apex_L2_Eg realm="{realm}",
apex_l2_eg_app_id="{app_id}",
apex_l2_eg_nonce="{random_nonce}",
apex_l2_eg_signature_method="SHA256withRSA",
apex_l2_eg_signature="{base64_url_percent_encoded_signature}",
apex_l2_eg_timestamp="{unix_epoch_in_milliseconds}",
apex_l2_eg_version="1.0"Note: above sample is separated by lines for ease-of-reading, and new-line denotations are to be omitted in the actual request.
{realm} is the logical name of your application.
{app_id} is the APP ID credential supplied upon onboarding,
{random_nonce} is an unique randomly generated text used for replay prevention,
{signature_algorithm} is the signature algorithm of the authenticating API gateway.
SHA256withRSA{base64_url_percent_encoded_signature} is the binary of the generated signature encoded in Base64 URL-safe format,
{unix_epoch_in_milliseconds} is the UNIX epoch time in milliseconds, and
apex_l2_eg_version="1.0" parameter is optional, and when emitted the value has to be 1.0.
NodeJS // generates the security headers for calling API Gateway
function generateAuthorizationHeader(url, params, method, strContentType, authType, appId, keyCertContent, passphrase, realm) {
if (authType == "L2") {
return generateSHA256withRSAHeader(url, params, method, strContentType, appId, keyCertContent, passphrase, realm);
} else {
return "";
}
};
// Signing Your Requests
function generateSHA256withRSAHeader(url, params, method, strContentType, appId, keyCertContent, keyCertPassphrase, realm) {
var nonceValue = nonce();
var timestamp = (new Date).getTime();
// A) Construct the Authorisation Token Parameters
var defaultApexHeaders = {
"apex_l2_eg_app_id": appId, // App ID assigned to your application
"apex_l2_eg_nonce": nonceValue, // secure random number
"apex_l2_eg_signature_method": "SHA256withRSA",
"apex_l2_eg_timestamp": timestamp, // Unix epoch time
"apex_l2_eg_version": "1.0"
};
// B) Forming the Base String
// Base String is a representation of the entire request (ensures message integrity)
// i) Normalize request parameters
var baseParams = sortJSON(_.merge(defaultApexHeaders, params));
var baseParamsStr = qs.stringify(baseParams);
baseParamsStr = qs.unescape(baseParamsStr); // url safe
// ii) concatenate request elements (HTTP method + url + base string parameters)
var baseString = method.toUpperCase() + "&" + url + "&" + baseParamsStr;
// C) Signing Base String to get Digital Signature
var signWith = {
key: fs.readFileSync(keyCertContent, 'utf8')
}; // Provides private key
// Load pem file containing the x509 cert & private key & sign the base string with it to produce the Digital Signature
var signature = crypto.createSign('RSA-SHA256')
.update(baseString)
.sign(signWith, 'base64');
// D) Assembling the Authorization Header
var strApexHeader = "apex_l2_eg realm=\"" + realm + // Defaults to 1st part of incoming request hostname
"\",apex_l2_eg_timestamp=\"" + timestamp +
"\",apex_l2_eg_nonce=\"" + nonceValue +
"\",apex_l2_eg_app_id=\"" + appId +
"\",apex_l2_eg_signature_method=\"SHA256withRSA\"" +
",apex_l2_eg_version=\"1.0\"" +
",apex_l2_eg_signature=\"" + signature +
"\"";
return strApexHeader;
};
NOTE: Entity-Person APIs only
Access Tokens are in JWT format. This JWT complies to the standard 'JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and Authorization Grants' (https://tools.ietf.org/html/rfc7523). You will need to verify the token with our public cert (provided during application onboarding).
NodeJS // Sample Code for Verifying & Decoding JWS or JWT
function verifyJWS(jws, publicCert) {
// verify token
// ignore notbefore check because it gives errors sometimes if the call is too fast.
try {
var decoded = jwt.verify(jws, fs.readFileSync(publicCert, 'utf8'), {
algorithms: ['RS256'],
ignoreNotBefore: true
});
return decoded;
}
catch(error) {
throw("Error with verifying and decoding JWS");
}
}
NOTE: Entity-Person APIs in Test and Production environments only
The response payload for the Entity-Person API (for staging and production environments) is encrypted in JWE (JSON Web Encryption) Compact Serialization format.
NodeJS // Sample Code for decrypting JWE
// Decrypt JWE using private key
function decryptJWE(header, encryptedKey, iv, cipherText, tag, privateKey) {
return new Promise((resolve, reject) => {
var keystore = jose.JWK.createKeyStore();
var data = {
"type": "compact",
"ciphertext": cipherText,
"protected": header,
"encrypted_key": encryptedKey,
"tag": tag,
"iv": iv,
"header": JSON.parse(jose.util.base64url.decode(header).toString())
};
keystore.add(fs.readFileSync(privateKey, 'utf8'), "pem")
.then(function(jweKey) {
// {result} is a jose.JWK.Key
jose.JWE.createDecrypt(jweKey)
.decrypt(data)
.then(function(result) {
resolve(JSON.parse(result.payload.toString()));
})
.catch(function(error) {
reject(error);
});
});
})
.catch (error => {
throw "Error with decrypting JWE";
})
}
In the response of Entity-Person API, each data item under the Person object comes with the following general structure:
| Field Name | Description |
|---|---|
| value | Value of data field (if applicable).
Refer to the schema in the specifications for details. |
| code | Value of data field in code (if applicable).
Refer to the schema in the specifications for details. |
| desc | Description code of data field (if applicable).
Refer to the schema in the specifications for details. |
| classification | Data classification of data field. Default 'C' - Confidential. |
| source | Source of data.
|
| lastupdated | Last updated date of data field. See "full-date" in http://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14 |
The RESTful API(s) uses HTTP specification standard status codes to indicate the success or failure of each request. Except gateway errors, the response content will be in the following JSON format:
{
"code": "integer (int32)",
"message": "string"
}Refer to the individual API definitions for the error codes you might encounter for each API.
Please refer to the links below for the following supporting materials where relevant:
For technical queries, contact support@myinfo.gov.sg.
For business queries, contact partner@myinfo.gov.sg.
The following are the available OAuth2 scopes for MyInfo Business APIs
| Security scheme type: | OAuth2 |
|---|---|
| authorizationCode OAuth Flow | Authorization URL: /authorise Token URL: /token Scopes:
|
Retrieves a sample Entity-Person data from MyInfo Business based on UEN and UIN/FIN.
This API does not use OAuth2.0 to perform authentication or authrisation, and does not require authorisation token and digital signature.
Note: Null value indicates that an attribute is unavailable.
| uen required | string <= 10 characters Example: "T15LP0010D" Required URL path parameter of the entity's unique entity number. This value can be obtained from the sub (uen_uinfin) in the decoded access_token. |
| uinfin required | string <= 9 characters Example: "S9203266C" Required URL path parameter of the person's uinfin. This value can be obtained from the sub (uen_uinfin) in the decoded access_token. |
| txnNo | string Transaction ID from requesting digital services for cross referencing. |
| attributes required | Array of string Example: "addresses,basic-profile,name,hanyupinyinname" Comma separated list of attributes requested. Possible attributes are listed in the scopes of the OAuth2 Security Schema above. |
| client_id required | string Unique ID for your application. |
OK.
Note:
Unauthorized. This could be due to the scenarios below:
Details will be given in the error object returned.
Forbidden. Digital service is not registered with MyInfo Business.
MESSAGE: 'Digital Service is invalid'
Not Found. UIN/FIN and/or UEN does not exist in MyInfo Business.
MESSAGE: 'UIN/FIN and/or UEN is invalid.'
Profile Incomplete. User/Entity registered for MyInfo Business less than 1 working day.
MESSAGE: 'Profile Incomplete'
Error with request parameters or headers. Error details will be provided in the response body
curl https://sandbox.api.myinfo.gov.sg/biz/v1/entity-person-sample/T15LP0010D/S9203266CThis API generates an access token when presented with a valid authcode obtained from the Authorise API. This token can then be used to request for the person and entity data that were consented.
| Authorization required | string Add token constructed containing the RSA digital signature of the base string. Refer to Security > Request Signing on how this token should be generated. Note: This header is not required when calling Sandbox API. |
| code required | string The authcode given by the authorise API. |
| grant_type | string Default: "authorization_code" Grant type for getting token (default "authorization_code") |
| client_secret required | string Secret key given to your application during onboarding. |
| client_id required | string Unique ID for your application. |
| redirect_uri required | string Your callback URL for MyInfo or MyInfo Business to validate. |
OK. returning a JSON object which contains the authorisation access token (JWT) that will be used to retrieve the data from MyInfo Business.
AuthCode error - missing, invalid, expired, revoked
Unexpected error. Error message will be in the response body
// function to prepare request for TOKEN API function createTokenRequest(code) { var cacheCtl = "no-cache"; var contentType = "application/x-www-form-urlencoded"; var method = "POST"; var request = null; // preparing the request with header and parameters // assemble params for Token API var strParams = "grant_type=authorization_code" + "&code=" + code + "&redirect_uri=" + _redirectUrl + "&client_id=" + _clientId + "&client_secret=" + _clientSecret; var params = querystring.parse(strParams); // assemble headers for Token API var strHeaders = "Content-Type=" + contentType + "&Cache-Control=" + cacheCtl; var headers = querystring.parse(strHeaders); // Sign request and add Authorization Headers var authHeaders = generateAuthorizationHeader( _tokenApiUrl, params, method, contentType, _authLevel, _clientId, _privateKeyContent, _clientSecret, _realm ); if (!_.isEmpty(authHeaders)) { _.set(headers, "Authorization", authHeaders); } var request = restClient.post(_tokenApiUrl); // Set headers if (!_.isUndefined(headers) && !_.isEmpty(headers)) request.set(headers); // Set Params if (!_.isUndefined(params) && !_.isEmpty(params)) request.send(params); return request; }
This API returns person and entity data from MyInfo Business when presented with a valid access token obtained from the Token API.
Note: Null value indicates that an attribute is unavailable.
| uen required | string <= 10 characters Example: "T15LP0010D" Required URL path parameter of the entity's unique entity number. This value can be obtained from the sub (uen_uinfin) in the decoded access_token. |
| uinfin required | string <= 9 characters Example: "S9203266C" Required URL path parameter of the person's uinfin. This value can be obtained from the sub (uen_uinfin) in the decoded access_token. |
| txnNo | string Transaction ID from requesting digital services for cross referencing. |
| attributes required | Array of string Example: "addresses,basic-profile,name,hanyupinyinname" Comma separated list of attributes requested. Possible attributes are listed in the scopes of the OAuth2 Security Schema above. |
| client_id required | string Example: "STG-180099999K-TEST01" Unique ID for your application. |
| Authorization required | string Add authorization token constructed containing the RSA digital signature of the base string. Refer to Security > Request Signing on how this token should be generated. Also include the access token (JWT) from /token API in your header prefixed with 'Bearer'. Note: Only the Bearer token is required when calling Sandbox API. |
OK.
Note:
Unauthorized. This could be due to the scenarios below:
Details will be given in the error object returned.
Forbidden. Digital service is not registered with MyInfo Business.
MESSAGE: 'Digital Service is invalid'
Not Found. UIN/FIN and/or UEN does not exist in MyInfo Business.
MESSAGE: 'UIN/FIN and/or UEN is invalid.'
Profile Incomplete. User/Entity registered for MyInfo Business less than 1 working day.
MESSAGE: 'Profile Incomplete'
Error with request parameters or headers. Error details will be provided in the response body
// function to prepare request for PERSON API function createPersonRequest(uinfin, validToken) { var url = _personApiUrl + "/" + uinfin + "/"; var cacheCtl = "no-cache"; var method = "GET"; var request = null; // assemble params for Person API var strParams = "client_id=" + _clientId + "&attributes=" + _attributes; var params = querystring.parse(strParams); // assemble headers for Person API var strHeaders = "Cache-Control=" + cacheCtl; var headers = querystring.parse(strHeaders); var authHeaders; // Sign request and add Authorization Headers authHeaders = generateAuthorizationHeader( url, params, method, "", // no content type needed for GET _authLevel, _clientId, _privateKeyContent, _clientSecret, _realm ); if (!_.isEmpty(authHeaders)) { _.set(headers, "Authorization", authHeaders + ",Bearer " + validToken); } else { // NOTE: include access token in Authorization header as "Bearer " (with space behind) _.set(headers, "Authorization", "Bearer " + validToken); } // invoke token API var request = restClient.get(url); // Set headers if (!_.isUndefined(headers) && !_.isEmpty(headers)) request.set(headers); // Set Params if (!_.isUndefined(params) && !_.isEmpty(params)) request.query(params); return request; }