Skip to main content

API Response Standards

Logic API follows standard HTTP conventions and OpenAPI 3.0 for all responses.

HTTP Status Codes​

Status CodeDescriptionWhen Used
200OKSuccessful GET, POST, PUT, DELETE operations
204No ContentA Single query that matches no record
400Bad RequestInput validation (ARGUMENT_VALIDATION_ERROR), pre-condition/condition failures (CONDITION_VIOLATION), or an unresolved endpoint
401UnauthorizedAuthorization policy not satisfied (UNAUTHORIZAD_ACCESS)
404Not FoundRead action record not found, download attachment not found, or global option set not found (NOT_FOUND)
500Internal Server ErrorUnhandled server-side error (EXCEPTION)
note

Only Single queries return 204. Multi queries return 200 OK with an empty array [], and Paginated queries return 200 OK with an empty data array when nothing matches.

Success Responses​

Create Action​

Returns the ID of the created record:

{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}

Update Action​

Returns an empty response body:

HTTP/1.1 200 OK
Content-Length: 0

Delete Action​

Returns an empty response body:

HTTP/1.1 200 OK
Content-Length: 0

Read Action / Single Query​

Returns the record directly:

{
"accountId": "a1b2c3d4-...",
"name": "Contoso Ltd",
"emailAddress1": "info@contoso.com"
}

Multi Query​

Returns an array of records:

[
{ "contactId": "c1-guid", "fullName": "Alice Johnson" },
{ "contactId": "c2-guid", "fullName": "Bob Williams" }
]

Paginated Query​

Returns a paginated result object:

{
"cursor": "eyJwYWdlIjoxfQ==",
"count": 20,
"totalRecordCount": 47,
"hasMoreRecords": true,
"data": [
{ "accountId": "a1-guid", "name": "Contoso Ltd" },
{ "accountId": "a2-guid", "name": "Fabrikam Inc" }
]
}

Process Actions​

Returns an empty response body (or output parameters if defined):

{}

Error Response Structure​

All errors follow a consistent structure:

{
"errorCode": "ERROR_CODE",
"errorMessage": "Human-readable description of the error"
}
FieldTypeDescription
errorCodeStringMachine-readable error identifier
errorMessageStringHuman-readable error description

Engine Error Codes​

The runtime emits a fixed set of errorCode values. Pre-condition failures additionally carry the message you configure on the pre-condition.

Error CodeHTTP StatusMeaning
ARGUMENT_VALIDATION_ERROR400A required input was missing or failed validation
CONDITION_VIOLATION400A pre-condition's condition was not satisfied
NOT_FOUND400 / 404The action/query/option set could not be resolved, or the record/attachment was not found
UNAUTHORIZAD_ACCESS401The authorization policy was not satisfied
EXCEPTION500An unhandled server-side error occurred
note

UNAUTHORIZAD_ACCESS is spelled exactly as shown in the engine (a known typo in the source). In non-development environments the EXCEPTION message is the generic text "Unexpected error while executing api."; in development it contains the full exception detail.

Validation Error (400)​

{
"errorCode": "ARGUMENT_VALIDATION_ERROR",
"errorMessage": "Required input 'name' was not provided"
}

Pre-condition Failure (400)​

{
"errorCode": "CONDITION_VIOLATION",
"errorMessage": "Cannot update inactive accounts"
}

Authorization Error (401)​

{
"errorCode": "UNAUTHORIZAD_ACCESS",
"errorMessage": "The user is not authorized to access this API."
}

Not Found (404)​

{
"errorCode": "NOT_FOUND",
"errorMessage": "The requested attachment was not found"
}

Internal Error (500)​

{
"errorCode": "EXCEPTION",
"errorMessage": "Unexpected error while executing api."
}

Best Practices for Handling Responses​

Check Status Codes​

Always check the HTTP status code before processing the response:

const response = await fetch('/sales/account/create', {
method: 'POST',
body: JSON.stringify(accountData)
});

if (response.ok) {
const { id } = await response.json();
console.log('Created account:', id);
} else {
const error = await response.json();
console.error('Error:', error.errorMessage);
}

Handle Empty Responses​

Some operations return empty responses (204 No Content):

const response = await fetch('/sales/get-account-by-id?accountId=' + id);

if (response.status === 204) {
// No record found (Single query)
return null;
}

return await response.json();

Parse Paginated Results​

For paginated queries, use the cursor for navigation:

async function fetchAllAccounts() {
let cursor = null;
const allAccounts = [];

do {
const url = cursor
? `/sales/search-accounts?cursor=${cursor}`
: '/sales/search-accounts';

const response = await fetch(url);
const { data, cursor: nextCursor, hasMoreRecords } = await response.json();

allAccounts.push(...data);
cursor = hasMoreRecords ? nextCursor : null;
} while (cursor);

return allAccounts;
}