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
| Status | Description |
|---|---|
200 | Success |
201 | Resource created |
400 | Bad request - Invalid parameters |
401 | Unauthorized - Invalid or missing authentication |
403 | Forbidden - Insufficient permissions |
404 | Not found - Resource doesn't exist |
409 | Conflict - Resource state conflict |
422 | Unprocessable - Validation failed |
429 | Too many requests - Rate limit exceeded |
500 | Server error |
Common Error Codes
| Code | Description |
|---|---|
VALIDATION_ERROR | Request validation failed |
AUTHENTICATION_ERROR | Invalid credentials |
AUTHORIZATION_ERROR | Insufficient permissions |
NOT_FOUND | Resource not found |
RATE_LIMIT_EXCEEDED | Too many requests |
DOCUMENT_ALREADY_SIGNED | Document cannot be modified |
Request correlation
Every response — success or error — includes two correlation headers:
| Header | Description |
|---|---|
x-request-id | A UUID identifying this request. Error bodies repeat it as error.requestId. |
traceparent | The 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);
}