Errors
Every v2 error has one shape:
{
"error": {
"code": "validation_failed",
"message": "Email address is not a valid email",
"request_id": "9f3a2c8e-...",
"details": [
{ "field": "email", "message": "is not a valid email" }
]
}
}
details is present on validation errors (one entry per field) and on a feature_disabled caused by one field (the field your account cannot set), and omitted otherwise. Quote the request_id when you contact support; it ties your request to our logs.
Sending back what you read never causes feature_disabled: on every write, a field of a feature your account does not use is accepted and changes nothing when it carries the value the API serves for that record (null and an empty or whitespace-only string count as equal, in either direction). On a create, any empty value is accepted and ignored: null, "" (or whitespace only), [], {}, or false for an on/off field. Only a different value is 403 feature_disabled.
| Status | code |
When |
|---|---|---|
| 400 | validation_failed |
A required parameter is missing, a parameter has the wrong type, or per_page is above the cap |
| 401 | unauthorized |
See Authentication |
| 403 | forbidden |
The key may not perform this operation |
| 403 | account_deactivated, api_disabled, insufficient_scope, feature_disabled |
See Authentication. feature_disabled names the feature in its message |
| 404 | not_found |
No record with that id in your account. An id that belongs to another account is also 404, never 403 |
| 409 | conflict |
The write would invalidate another open record; the conflict member names it. See below |
| 409 | conflict |
A party or project create or update raced another change storing the first value of the same custom field. Nothing was written; send the request again. This 409 carries no conflict member |
| 409 | idempotency_in_progress |
A request with the same Idempotency-Key is still running. See Idempotency |
| 409 | idempotency_not_replayable |
The Idempotency-Key cannot be replayed: what it created no longer exists, or the first response held a one-time value |
| 422 | validation_failed |
The record could not be saved; details names each field. Also used for an id in a body or query that is not in your account |
| 422 | signing_template_invalid |
The signing template cannot be sent as configured; the message names the template. See Document signing |
| 422 | idempotency_key_reused |
The Idempotency-Key was already used for a different request |
| 429 | rate_limited |
See Rate limits; carries a Retry-After header |
| 500 | internal_error |
Something failed on our side; we are alerted with the request_id. Safe to retry a read; check before retrying a write |
| 501 | not_implemented |
The endpoint exists in the reference but is not available yet |
| 502 | upstream_failed |
A service HoundDog depends on (the e-signature service, file storage) failed or timed out; nothing was kept. Retry with an Idempotency-Key |
Each operation's page lists the codes it can return.
Error messages are plain sentences meant for logs and support tickets, not for display to your end users.
Conflicts
A 409 conflict carries the record it conflicts with in its own member; details is omitted:
{
"error": {
"code": "conflict",
"message": "This party already has an open request for this template",
"request_id": "9f3a2c8e-...",
"conflict": { "resource": "signing_request", "id": 9012 }
}
}
Read that record named by resource and id, then decide: each conflicting write accepts a flag to go ahead.
signing_request: sendsupersede: true(see Document signing).w9: sendreplace: true(see W-9s).
Order of checks on W-9 and document signing writes
On those writes, the checks run in this order and the first failure answers:
- Authentication and the account gates (401, 403), see Authentication.
- The feature gate (403
feature_disabled). - Ids in the path (404).
- The body and query (400 for malformed parameters, then 422
validation_failedorsigning_template_invalidfor what is known without calling another service). - Conflicts (409
conflict). - Calls to another service (422
signing_template_invalid, 502upstream_failed).
So a request that would fail validation never receives a conflict, and a conflict is reported before any call to another service is made.
One exception to the order: parameter validation (types, required parameters, allowed values) runs before the endpoint body, so a malformed parameter (400) can be reported before the feature gate (step 2) and before an unknown id in the path (step 3). This order is stated for those writes only; other endpoints follow the same layers but make no promise about their order.
A note on v1
v1 keeps its original string-shaped errors, {"error": "..."}, and will for as long as v1 is served. Only v2 uses the structured shape above.