Skip to main content

Error Handling

The API uses standard HTTP status codes and returns detailed error information in JSON format.

Error Response Format

{
"error": {
"code": "VALIDATION_ERROR",
"message": "The request body is invalid",
"requestId": "a7f8c2b1-3d4e-4f5a-9b0c-1d2e3f4a5b6c",
"details": [
{
"field": "email",
"message": "Must be a valid email address"
}
]
}
}

The requestId is the correlation id for the request (see Request correlation below). It is identical to the x-request-id response header.

HTTP Status Codes

StatusDescription
200Success
201Resource created
400Bad request - Invalid parameters
401Unauthorized - Invalid or missing authentication
403Forbidden - Insufficient permissions
404Not found - Resource doesn't exist
409Conflict - Resource state conflict
422Unprocessable - Validation failed
429Too many requests - Rate limit exceeded
500Server error

Common Error Codes

CodeDescription
VALIDATION_ERRORRequest validation failed
AUTHENTICATION_ERRORInvalid credentials
AUTHORIZATION_ERRORInsufficient permissions
NOT_FOUNDResource not found
RATE_LIMIT_EXCEEDEDToo many requests
DOCUMENT_ALREADY_SIGNEDDocument cannot be modified

Request correlation

Every response — success or error — includes two correlation headers:

HeaderDescription
x-request-idA UUID identifying this request. Error bodies repeat it as error.requestId.
traceparentThe W3C Trace Context identifier for this request.

Quote x-request-id when you contact support — it lets us locate the exact request in seconds. It is also a stable join key for correlating your own logs with the API.

const response = await fetch('https://api.propper.ai/v1/sign/agreements', {
headers: { Authorization: `Bearer ${apiKey}` },
});

const requestId = response.headers.get('x-request-id');
if (!response.ok) {
const body = await response.json();
// requestId === body.error.requestId
console.error(`Request ${requestId} failed: ${body.error.code}${body.error.message}`);
}

The x-request-id value is the same 128 bits as the trace-id segment of traceparent, just formatted as a UUID. To tie a multi-call workflow together under a single trace, send your own traceparent header on each request and the API will adopt it:

traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01

Handling Errors

try {
const response = await fetch('https://api.propper.ai/v1/sign/agreements', {
method: 'POST',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(agreementData),
});

if (!response.ok) {
const error = await response.json();
console.error(
`Error: ${error.error.code} - ${error.error.message} (request ${error.error.requestId})`,
);
}
} catch (err) {
console.error('Network error:', err);
}