Registrations Services
To bind mobile device with a particular user ID, the user needs to create a registration. Registration is created via an “activation code”. After the user scans the code, the registration needs to be committed. At any point, you can obtain the registration status for a user with given user ID and registration ID.
Possible Error Codes
Error Code | HTTP Status Code | Description |
---|---|---|
ERROR_REGISTRATION_NOT_FOUND |
400 |
Indicates no registration is found for the provided user or the user does not have access to the registrations. |
ERROR_REGISTRATION_NOT_ALLOWED |
400 |
Indicates registration is not allowed because another registration is already in progress for the user. |
ERROR_REGISTRATION_CHANGE |
400 |
Indicates the registration is in an invalid state for the requested action. |
ERROR_REQUEST |
400 |
Indicates the request did not pass structural validation (mandatory field is null, invalid field type, etc.). |
HTTP_401 |
401 |
Unauthorized access attempt. This occurs when invalid credentials are provided. |
ERROR_INTERNAL_API |
500 |
An internal server error occurred, potentially due to misconfiguration. Check your deployment configuration for errors. |
Services
post /v2/registrations Create New Registration
Initiate a new registration for provided user ID. The service returns a fully prepared content for the registration QR code - you can simply grab the response and encode it using your preferred QR code generator library.
When creating registration, you can also set OTP value and OTP validation mode. OTP represents additional credentials used during the activation flow.
Request
{
"userId": "$USER_ID",
"appId": "$APP_ID",
"otp": "$OTP",
"otpValidation": "$OTP_VALIDATION",
"flags": [
"$FLAG"
],
"timestampRegistrationExpire": "$TIMESTAMP_REGISTRATION_EXPIRE"
}
Query Params
Param | Type | Description |
---|---|---|
incompleteStatusCheck |
boolean |
Indicates if the call should check if a registration is already in progress and return error if it is. Default: false |
Request Params
Attribute | Type | Description |
---|---|---|
userId * |
String |
ID of a user for whom to create new registration. |
appId * |
String |
ID of an application. |
otpValidation |
String |
The way OTP is presented during the process, can be NONE , ON_KEY_EXCHANGE or ON_COMMIT (default: NONE ). |
otp |
String |
Optional OTP value. |
flags |
String[] |
Flags which should be stored together with the registration record. |
timestampRegistrationExpire |
DateTime |
An optional timestamp indicating the timeframe by which the registration process must start. |
Response
During successful registration, the API will return the activation code data. You can map the activationQrCodeData
attribute in the response directly to the QR code data. Additionally, a registrationId
value is returned which can be
used later on when referring to the registration record. In PowerAuth server this value is stored as the activationId
record.
{
"activationQrCodeData": "23456-DEFGH-77777-77777#MEUCIDFFx60vcqDcqRY014uE+5CH38lJ/NOVNoaGHWpE+7fVAiEA8LsWi9AvRJPwRnlSSOB3O080mXd6YbRt74DLQqrrLlg=",
"activationCode": "23456-DEFGH-77777-77777",
"activationCodeSignature": "MEUCIDFFx60vcqDcqRY014uE+5CH38lJ/NOVNoaGHWpE+7fVAiEA8LsWi9AvRJPwRnlSSOB3O080mXd6YbRt74DLQqrrLlg=",
"registrationId": "8819ac31-ad29-40d1-ac60-1b54293abe61"
}
Attribute | Type | Description |
---|---|---|
activationQrCodeData * |
String |
String for the activation QR code. |
activationCode * |
String |
Activation code value. |
activationCodeSignature * |
String |
Activation code ECDSA signature. |
registrationId * |
String |
ID of created registration. |
Registration failed due to a business logic problem.
{
"status": "ERROR",
"responseObject": {
"code": "ERROR_REGISTRATION_NOT_ALLOWED",
"message": "Registration is already in progress"
}
}
Possible error states are:
ERROR_REGISTRATION_NOT_FOUND
- When user does not have access to the registrations.ERROR_REGISTRATION_NOT_ALLOWED
- When registration is not allowed because another registration is already in progress for the user.ERROR_REQUEST
- Request did not pass a structural validation (mandatory field is null, invalid field type, etc.).
Invalid username or password was provided while calling the service.
{
"status": "ERROR",
"responseObject": {
"code": "HTTP_401",
"message": "Unauthorized"
}
}
Error occurred while calling the internal service. This can happen only as a result of misconfiguration. Check your deployment configuration for errors.
{
"status": "ERROR",
"responseObject": {
"code": "ERROR_INTERNAL_API",
"message": "Unable to call upstream service"
}
}
post /v2/registrations/{registrationId}/commit Commit New Registration
Commit the new registration after the mobile device exchanged the data with the server-side in order to make the registration active.
In case the registration was specified with ON_COMMIT
OTP validation mode, OTP value has to be provided to complete
the registration.
Only registrations that are in the PENDING_COMMIT
state can be committed. Check the registration status by
calling GET /v2/registrations
before the commit.
Request
{
"externalUserId": "$EXTERNAL_USER_ID",
"otp": "$OTP"
}
Path Params
Attribute | Type | Description |
---|---|---|
registrationId * |
String |
ID of registration to be committed. |
Request Params
Attribute | Type | Description |
---|---|---|
externalUserId |
String |
ID of an external user who initiated this action (i.e., a call center operator or admin). |
otp |
String |
OTP value (only for ON_COMMIT validation mode set when creating the registration |
Response
{
"status": "OK"
}
Attribute | Type | Description |
---|---|---|
status * |
String |
Fixed value OK . |
Registration commit failed due to a business logic problem.
{
"status": "ERROR",
"responseObject": {
"code": "ERROR_REGISTRATION_NOT_FOUND",
"message": "Registration cannot be committed, unexpected state: ..."
}
}
Possible error states are:
ERROR_REGISTRATION_NOT_FOUND
- When registration does not exist for given user and application or user does not have access to the registration.ERROR_REGISTRATION_CHANGE
- When the registration is in invalid state.ERROR_REQUEST
- Request did not pass a structural validation (mandatory field is null, invalid field type, etc.).
Invalid username or password was provided while calling the service.
{
"status": "ERROR",
"responseObject": {
"code": "HTTP_401",
"message": "Unauthorized"
}
}
Error occurred while calling the internal service. This can happen only as a result of misconfiguration. Check your deployment configuration for errors.
{
"status": "ERROR",
"responseObject": {
"code": "ERROR_INTERNAL_API",
"message": "Unable to call upstream service"
}
}
get /v2/registrations/{registrationId} Get Registration Detail
Get the registration detail for a given registration identifier.
Request
Path Params
Param | Type | Description |
---|---|---|
registrationId * |
String |
ID of registration record. |
Response
The response body attributes depend on the registration status. There are four possible response structures:
- Created Registration
- Pending Commit Registration
- Active Registration
- Blocked Registration
- Removed Registration
Created Registration
The registration was just created, no other activity occurred. The expected step at this stage is exchange between mobile authenticator and server-side components. This step is initiated by scanning the activation QR code with a mobile app.
{
"registrationId": "8819ac31-ad29-40d1-ac60-1b54293abe61",
"registrationStatus": "CREATED",
"applicationId": "my-application",
"userId": "user_id",
"activationQrCodeData": "NTF5I-R3KHV-SZN6E-ISYBA#MEYCIQC99lzXIlz3V3nLFBz1MyN0EV6y7IZDdheI14BetT/J5QIhAJReYRX8GKQYm1YzExJatYUBLHJgvhCLnjYeltVYDr1a",
"activationCode": "NTF5I-R3KHV-SZN6E-ISYBA",
"activationCodeSignature": "MEYCIQC99lzXIlz3V3nLFBz1MyN0EV6y7IZDdheI14BetT/J5QIhAJReYRX8GKQYm1YzExJatYUBLHJgvhCLnjYeltVYDr1a",
"flags": [
"FLAG_1"
],
"timestampCreated": 1617787702781,
"timestampLastUsed": 1617787702781
}
Attribute | Type | Description |
---|---|---|
registrationId * |
String |
Registration identifier. |
registrationStatus * |
String |
Fixed value CREATED . |
applicationId * |
String |
Application identifier. |
userId * |
String |
User identifier. |
activationQrCodeData * |
String |
String for the activation QR code. |
activationCode * |
String |
Activation code value. |
activationCodeSignature * |
String |
Activation code ECDSA signature. |
flags * |
String[] |
Registration flags. |
timestampCreated * |
Long |
Unix timestamp in milliseconds, represents when the registration was created. |
timestampLastUsed * |
Long |
Unix timestamp in milliseconds, represents when the registration was last used. |
Pending Commit Registration
The exchange between mobile authenticator and server-side components is completed and activation is ready to be committed, which makes it usable for operation approval. In this state, the activation fingerprint contains the value representing exchanged cryptographic material. You can show the value in both mobile app and web interface to let user check that the exchange completed successfully.
{
"registrationId": "8819ac31-ad29-40d1-ac60-1b54293abe61",
"registrationStatus": "PENDING_COMMIT",
"applicationId": "my-application",
"userId": "user_id",
"name": "iPhone",
"platform": "ios",
"deviceInfo": "iPhone10,6",
"activationFingerprint": "52649917",
"flags": [
"FLAG_1"
],
"timestampCreated": 1617787702781,
"timestampLastUsed": 1617787713705
}
Attribute | Type | Description |
---|---|---|
registrationId * |
String |
Registration identifier. |
registrationStatus * |
String |
Fixed value PENDING_COMMIT . |
applicationId * |
String |
Application identifier. |
userId * |
String |
User identifier. |
name * |
String |
Name of the registration, usually a device name. |
platform * |
String |
Platform of the mobile client, ios or android . |
deviceInfo * |
String |
Information about the device model, i.e. iPhone10,6 |
activationFingerprint * |
String |
Numerical value representing the exchanged data. You may show this value in the web interface to allow user check that the same value is displayed on the mobile device and hence exchange was completed successfully. |
flags * |
String[] |
Registration flags. |
timestampCreated * |
Long |
Unix timestamp in milliseconds, represents when the registration was created. |
timestampLastUsed * |
Long |
Unix timestamp in milliseconds, represents when the registration was last used. |
Active Registration
The registration is active, and it can be used to approve operations.
{
"registrationId": "8819ac31-ad29-40d1-ac60-1b54293abe61",
"registrationStatus": "ACTIVE",
"applicationId": "my-application",
"userId": "user_id",
"name": "iPhone",
"platform": "ios",
"deviceInfo": "iPhone10,6",
"flags": [
"FLAG_1"
],
"timestampCreated": 1617787702781,
"timestampLastUsed": 1617787714421
}
Attribute | Type | Description |
---|---|---|
registrationId * |
String |
Registration identifier. |
registrationStatus * |
String |
Fixed value ACTIVE . |
applicationId * |
String |
Application identifier. |
userId * |
String |
User identifier. |
name * |
String |
Name of the registration, usually a device name. |
platform * |
String |
Platform of the mobile client, ios or android . |
deviceInfo * |
String |
Information about the device model, i.e. iPhone10,6 |
flags * |
String[] |
Registration flags. |
timestampCreated * |
Long |
Unix timestamp in milliseconds, represents when the registration was created. |
timestampLastUsed * |
Long |
Unix timestamp in milliseconds, represents when the registration was last used. |
Blocked Registration
The registration is blocked, either because of too many failed attempts to authenticate, or because it was actively blocked by the user, admin, call center, or any other similar mechanism. The blocked registration cannot be used to approve operations, it has to be unblocked first, or the user needs to re-activate the device.
{
"registrationId": "8819ac31-ad29-40d1-ac60-1b54293abe61",
"registrationStatus": "BLOCKED",
"blockedReason": "NOT_SPECIFIED",
"applicationId": "my-application",
"userId": "user_id",
"name": "iPhone",
"platform": "ios",
"deviceInfo": "iPhone10,6",
"flags": [
"FLAG_1"
],
"timestampCreated": 1617787702781,
"timestampLastUsed": 1617787715839
}
Attribute | Type | Description |
---|---|---|
registrationId * |
String |
Registration identifier. |
registrationStatus * |
String |
Fixed value BLOCKED . |
blockedReason |
String |
Additional information about the reason for blocking. Freeform enum value, with two reserved values MAX_FAILED_ATTEMPTS and NOT_SPECIFIED . |
applicationId * |
String |
Application identifier. |
userId * |
String |
User identifier. |
name * |
String |
Name of the registration, usually a device name. |
platform * |
String |
Platform of the mobile client, ios or android . |
deviceInfo * |
String |
Information about the device model, i.e. iPhone10,6 |
flags * |
String[] |
Registration flags. |
timestampCreated * |
Long |
Unix timestamp in milliseconds, represents when the registration was created. |
timestampLastUsed * |
Long |
Unix timestamp in milliseconds, represents when the registration was last used. |
Removed Registration
The registration is removed, the server returns as much information as was available at the time the registration was removed.
For example, activations that were in the CREATED
state and got removed (or expired) cannot provide a device name,
platform and device info.
{
"registrationId": "8819ac31-ad29-40d1-ac60-1b54293abe61",
"registrationStatus": "REMOVED",
"applicationId": "my-application",
"userId": "user_id",
"name": "iPhone",
"platform": "ios",
"deviceInfo": "iPhone10,6",
"flags": [
"FLAG_1"
],
"timestampCreated": 1617787702781,
"timestampLastUsed": 1617787715839
}
Attribute | Type | Description |
---|---|---|
registrationId * |
String |
Registration identifier. |
registrationStatus * |
String |
Fixed value BLOCKED . |
blockedReason |
String |
Additional information about the reason for blocking. Freeform enum value, with two reserved values MAX_FAILED_ATTEMPTS and NOT_SPECIFIED . |
applicationId * |
String |
Application identifier. |
userId * |
String |
User identifier. |
name * |
String |
Name of the registration, usually a device name. Only available if the activation made it past the CREATED state before removal. |
platform * |
String |
Platform of the mobile client, ios or android . Only available if the activation made it past the CREATED state before removal. |
deviceInfo * |
String |
Information about the device model, i.e. iPhone10,6 . Only available if the activation made it past the CREATED state before removal. |
flags * |
String[] |
Registration flags. |
timestampCreated * |
Long |
Unix timestamp in milliseconds, represents when the registration was created. |
timestampLastUsed * |
Long |
Unix timestamp in milliseconds, represents when the registration was last used. |
Registration status failed due to a business logic problem.
{
"status": "ERROR",
"responseObject": {
"code": "ERROR_REQUEST",
"message": "Required String parameter 'registrationId' is not present"
}
}
Possible error states are:
ERROR_REQUEST
- Request did not pass a structural validation (mandatory field is null, invalid field type, etc.)ERROR_REGISTRATION_NOT_FOUND
- When user does not have access to the registration.
Invalid username or password was provided while calling the service.
{
"status": "ERROR",
"responseObject": {
"code": "HTTP_401",
"message": "Unauthorized"
}
}
Error occurred while calling the internal service. This can happen only as a result of misconfiguration. Check your deployment configuration for errors.
{
"status": "ERROR",
"responseObject": {
"code": "ERROR_INTERNAL_API",
"message": "Unable to call upstream service"
}
}
get /v2/registrations Get Registration List
Get the registration list for a given user.
Request
Query Params
Param | Type | Description |
---|---|---|
userId * |
String |
ID of the user for whom the registration list is being retrieved. |
removed |
boolean |
Optional flag to indicate whether removed registrations should be included in the response. |
pageNumber |
Integer |
Optional page number to retrieve (default 0). |
pageSize |
Integer |
Optional number of items to return per page (default 500). |
Response
The response body contains list of registrations. You can obtain additional details by calling the Get Registration Detail endpoint.
The example below shows two registrations, one in CREATED
state and another one in ACTIVE
state.
{
"registrations": [
{
"registrationId": "8819ac31-ad29-40d1-ac60-1b54293abe61",
"registrationStatus": "CREATED",
"applicationId": "my-application",
"flags": [
"FLAG_1"
],
"timestampCreated": 1617787702781,
"timestampLastUsed": 1617787715839
},
{
"registrationId": "59f1cd5b-63a4-4cc3-82c7-544c246cfa77",
"registrationStatus": "ACTIVE",
"applicationId": "my-application",
"name": "iPhone SE",
"platform": "ios",
"deviceInfo": "iphone10,6",
"flags": [
"FLAG_2"
],
"timestampCreated": 1617787702781,
"timestampLastUsed": 1617787715839
}
]
}
Attribute | Type | Description |
---|---|---|
registrations[].registrationId * |
String |
Registration identifier. |
registrations[].registrationStatus * |
String |
Registration status: CREATED , PENDING_COMMIT , ACTIVE , or BLOCKED . |
registrations[].applicationId * |
String |
Application identifier. |
registrations[].name |
String |
Name of the registration, usually a device name. Not present for activation that only went through CREATED state. |
registrations[].platform |
String |
Platform information, one of: ios , android . Not present for activation that only went through CREATED state. |
registrations[].deviceInfo |
String |
Additional device information. Not present for activation that only went through CREATED state. |
registrations[].flags * |
String[] |
Registration flags. |
registrations[].timestampCreated * |
Long |
Unix timestamp in milliseconds, represents when the registration was created. |
registrations[].timestampLastUsed * |
Long |
Unix timestamp in milliseconds, represents when the registration was last used. |
Request validation failed.
{
"status": "ERROR",
"responseObject": {
"code": "ERROR_REQUEST",
"message": "Required String parameter 'userId' is not present"
}
}
ERROR_REQUEST
- Request did not pass a structural validation (mandatory field is null, invalid field type, etc.).ERROR_REGISTRATION_NOT_FOUND
- When user does not have access to the registrations.
Invalid username or password was provided while calling the service.
{
"status": "ERROR",
"responseObject": {
"code": "HTTP_401",
"message": "Unauthorized"
}
}
Error occurred while calling the internal service. This can happen only as a result of misconfiguration. Check your deployment configuration for errors.
{
"status": "ERROR",
"responseObject": {
"code": "ERROR_INTERNAL_API",
"message": "Unable to call upstream service"
}
}
put /v2/registrations/{registrationId} Edit Registration Status
Edit the registration status, for example: block, unblock or delete registration. The method checks if the particular change is allowed for the current registration status.
The following actions are allowed for particular registration states:
CREATED
=>REMOVE
PENDING_COMMIT
=>REMOVE
ACTIVE
=>BLOCK
,REMOVE
BLOCKED
=>UNBLOCK
,REMOVE
Request
{
"change": "$CHANGE",
"externalUserId": "$EXTERNAL_USER_ID",
"blockReason": "$BLOCK_REASON"
}
Path Params
Param | Type | Description |
---|---|---|
registrationId * |
String |
ID of registration record. |
Request Params
Attribute | Type | Description |
---|---|---|
change * |
String |
Type of the requested change. |
externalUserId |
String |
ID of an external user who created this change, i.e., admin or call center operator. |
blockReason |
String |
Reason for blocking the activation. |
Possible changes are:
BLOCK
- Block the active registration.UNBLOCK
- Unblock the blocked registration.REMOVE
- Remove the registration, can be called in any registration state.
Response
{
"status": "OK"
}
Attribute | Type | Description |
---|---|---|
status * |
String |
Fixed value OK . |
Registration status change failed due to a business logic problem.
{
"status": "ERROR",
"responseObject": {
"code": "ERROR_REGISTRATION_CHANGE",
"message": "Activation is BLOCKED, you can only UNBLOCK or REMOVE it."
}
}
{
"status": "ERROR",
"responseObject": {
"code": "ERROR_REGISTRATION_NOT_FOUND",
"message": "Registration not found for state change"
}
}
Possible error states are:
ERROR_REGISTRATION_NOT_FOUND
- Registration is not found or user does not have access to the registration.ERROR_REGISTRATION_CHANGE
- The requested change cannot be performed due to invalid initial state.
Invalid username or password was provided while calling the service.
{
"status": "ERROR",
"responseObject": {
"code": "HTTP_401",
"message": "Unauthorized"
}
}
Error occurred while calling the internal service. This can happen only as a result of misconfiguration. Check your deployment configuration for errors.
{
"status": "ERROR",
"responseObject": {
"code": "ERROR_INTERNAL_API",
"message": "Unable to call upstream service"
}
}
put /v2/registrations/{registrationId}/name Update Registration
Update the registration name.
Request
{
"name": "$NAME",
"externalUserId": "$EXTERNAL_USER_ID"
}
Path Params
Param | Type | Description |
---|---|---|
registrationId * |
String |
ID of registration record. |
Request Params
Attribute | Type | Description |
---|---|---|
name * |
String |
Name to be changed. |
externalUserId * |
String |
ID of an external user who created this change, i.e., admin or call center operator. |
Response
{
"status": "OK"
}
Attribute | Type | Description |
---|---|---|
status * |
String |
Fixed value OK . |
Registration update failed due to a business logic problem.
{
"status": "ERROR",
"responseObject": {
"code": "ERROR_REGISTRATION_NOT_FOUND",
"message": "Registration not found"
}
}
Possible error states are:
ERROR_REGISTRATION_NOT_FOUND
- Registration is not found or user does not have access to the registration.
Invalid username or password was provided while calling the service.
{
"status": "ERROR",
"responseObject": {
"code": "HTTP_401",
"message": "Unauthorized"
}
}
Error occurred while calling the internal service. This can happen only as a result of misconfiguration. Check your deployment configuration for errors.
{
"status": "ERROR",
"responseObject": {
"code": "ERROR_INTERNAL_API",
"message": "Unable to call upstream service"
}
}
delete /v2/registrations/{registrationId} Remove Registration
Remove the registration.
The call is equivalent to calling PUT /v2/registrations/{registrationId}
with the REMOVE
change.
Request
Path Params
Param | Type | Description |
---|---|---|
registrationId * |
String |
ID of registration record. |
Response
{
"status": "OK"
}
Attribute | Type | Description |
---|---|---|
status * |
String |
Fixed value OK . |
Registration removal failed due to a business logic problem.
{
"status": "ERROR",
"responseObject": {
"code": "ERROR_REGISTRATION_NOT_FOUND",
"message": "Registration not found for state change"
}
}
Possible error states are:
ERROR_REGISTRATION_NOT_FOUND
- Registration is not found or user does not have access to the registration.
Invalid username or password was provided while calling the service.
{
"status": "ERROR",
"responseObject": {
"code": "HTTP_401",
"message": "Unauthorized"
}
}
Error occurred while calling the internal service. This can happen only as a result of misconfiguration. Check your deployment configuration for errors.
{
"status": "ERROR",
"responseObject": {
"code": "ERROR_INTERNAL_API",
"message": "Unable to call upstream service"
}
}
post /v2/registrations/{registrationId}/flags Add Registration Flags
Add registration flags to a registration record.
Request
{
"flags": [
"$FLAG"
]
}
Path Params
Param | Type | Description |
---|---|---|
registrationId * |
String |
ID of registration record. |
Request Params
Attribute | Type | Description |
---|---|---|
flags * |
String[] |
Array with flags to be added to the registration record. |
Response
{
"status": "OK"
}
Attribute | Type | Description |
---|---|---|
status * |
String |
Fixed value OK . |
Flag addition failed due to a business logic problem.
{
"status": "ERROR",
"responseObject": {
"code": "ERROR_REGISTRATION_NOT_FOUND",
"message": "Registration not found"
}
}
Possible error states are:
ERROR_REGISTRATION_NOT_FOUND
- Registration is not found or user does not have access to the registration.
Invalid username or password was provided while calling the service.
{
"status": "ERROR",
"responseObject": {
"code": "HTTP_401",
"message": "Unauthorized"
}
}
Error occurred while calling the internal service. This can happen only as a result of misconfiguration. Check your deployment configuration for errors.
{
"status": "ERROR",
"responseObject": {
"code": "ERROR_INTERNAL_API",
"message": "Unable to call upstream service"
}
}
post /v2/registrations/{registrationId}/flags/remove Remove Registration Flags
Remove registration flags for a registration record.
Request
{
"flags": [
"$FLAG"
]
}
Path Params
Param | Type | Description |
---|---|---|
registrationId * |
String |
ID of registration record. |
Attribute | Type | Description |
---|---|---|
flags * |
String[] |
Array with flags to be deleted for the registration record. |
Response
{
"status": "OK"
}
Attribute | Type | Description |
---|---|---|
status * |
String |
Fixed value OK . |
Flag deletion failed due to a business logic problem.
{
"status": "ERROR",
"responseObject": {
"code": "ERROR_REGISTRATION_NOT_FOUND",
"message": "Registration not found"
}
}
Possible error states are:
ERROR_REGISTRATION_NOT_FOUND
- Registration is not found or user does not have access to the registration.
Invalid username or password was provided while calling the service.
{
"status": "ERROR",
"responseObject": {
"code": "HTTP_401",
"message": "Unauthorized"
}
}
Error occurred while calling the internal service. This can happen only as a result of misconfiguration. Check your deployment configuration for errors.
{
"status": "ERROR",
"responseObject": {
"code": "ERROR_INTERNAL_API",
"message": "Unable to call upstream service"
}
}