Skip to main content

API Response Standards

API Builder 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;
}