API Response Standards
API Builder follows standard HTTP conventions and OpenAPI 3.0 for all responses.
HTTP Status Codes
| Status Code | Description | When Used |
|---|---|---|
| 200 | OK | Successful GET, POST, PUT, DELETE operations |
| 204 | No Content | A Single query that matches no record |
| 400 | Bad Request | Input validation (ARGUMENT_VALIDATION_ERROR), pre-condition/condition failures (CONDITION_VIOLATION), or an unresolved endpoint |
| 401 | Unauthorized | Authorization policy not satisfied (UNAUTHORIZAD_ACCESS) |
| 404 | Not Found | Read action record not found, download attachment not found, or global option set not found (NOT_FOUND) |
| 500 | Internal Server Error | Unhandled server-side error (EXCEPTION) |
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"
}
| Field | Type | Description |
|---|---|---|
| errorCode | String | Machine-readable error identifier |
| errorMessage | String | Human-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 Code | HTTP Status | Meaning |
|---|---|---|
ARGUMENT_VALIDATION_ERROR | 400 | A required input was missing or failed validation |
CONDITION_VIOLATION | 400 | A pre-condition's condition was not satisfied |
NOT_FOUND | 400 / 404 | The action/query/option set could not be resolved, or the record/attachment was not found |
UNAUTHORIZAD_ACCESS | 401 | The authorization policy was not satisfied |
EXCEPTION | 500 | An unhandled server-side error occurred |
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;
}