Error responses and codes
The error body, the error headers, when to retry, and every error code the REFRACT Dispatcher returns to a caller, grouped by area.
This page lists every error code a caller of the REFRACT Dispatcher API can receive: /api/render, the Power Platform connector routes (/api/gateway/v1/...), and the workflow, eSign, Delivery, batch, document access, and verification routes. It covers what an error answer looks like, which headers carry the reason, and when a request may be sent again.
The signing portal's own calls (between a signer's browser, the portal, and the Dispatcher) use further codes. They are not part of this contract and are not listed here.
Release
Every code on this page is returned by the current release. A code that the next release adds is marked Available after the next release until that release is deployed.
The Error Body
A refusal answers with a JSON body:
{
"error": "Service Unavailable",
"code": "LICENSE_UNAVAILABLE",
"message": "The licensing service did not answer.",
"correlationId": "3f2c9a1e-7b4d-4c1a-9e2f-5d6b8a0c1e47",
"retryable": true,
"detail": "The licensing service did not answer."
}| Field | Present | Meaning |
|---|---|---|
code | Every 4xx and 503 | The stable value to branch on. A route that names no code of its own gets one from the status, such as BAD_REQUEST or NOT_FOUND (see Requests). |
message | Every 4xx and 503 | A sentence in the Dispatcher's own wording, fit to show to a person. Do not parse it. |
correlationId | Every 4xx and 503; null when the request failed before one was assigned | The ID support uses to find the request in the Dispatcher's log. The X-Refract-CorrelationId header carries it too. |
retryable | Only on answers that say whether trying again can help | true: the same request can succeed later; wait for Retry-After. false: it cannot until something is fixed. Absent: do not retry. |
detail | On some codes | More about the cause. On some routes it repeats message. Do not branch on it. |
error | Every JSON error answer | A short label kept for older clients. Branch on code, not on error. |
One 503 has error and code only: consent_layer_unavailable when it is found after the signing request was recorded (the request is then cancelled).
Some codes add fields beside these: feature (FEATURE_NOT_LICENSED), role (ROLE_MISSING), setting (SECTION508_SETTING_REFUSED), failedStandards (ACCESSIBILITY_CHECK_FAILED), state (WORKFLOW_STATE_CHANGED), problems (WORKFLOW_ROUTING_INVALID), fieldErrors (WORKFLOW_INITIAL_DATA_INVALID), and plan and expiresAt (the licence codes from /api/render).
Answers With a PDF Body
A render that fails for a reason of the service's own answers 500 with an error-report PDF as the body. So does an eSign or Delivery step refused after the document was rendered and stored; a workflow refused after the document was stored answers 422 the same way. The code is in the X-Refract-ErrorCode header, not in a body. The tables below mark these answers PDF, and after render when the document already exists.
Answers Without a Code
A few answers carry no code at all. Handle them by status:
- The explain and accessibility trace routes (
/api/explain/...,/api/accessibility/...) answer their4xxand500witherroronly. - A
500or502JSON answer from a route other than/api/rendercarrieserror, and sometimesdetail, but no code. - An unexpected exception that no route handles answers
500with an empty body. - A failed operation reported by
GET /api/operation-status/...answers200withstatus: "failed"and afailureReasonsentence.
Error Headers
| Header | Present on | Value |
|---|---|---|
Retry-After | Every answer with "retryable": true, the 429 rate limit, and some 503s | Seconds to wait before the next try. |
X-Refract-ErrorCode | Every answer with an error-report PDF body, and the 503 GENERATED_DOCUMENT_NOT_STORED | The code. The same code a JSON body gives for the same condition. |
X-Refract-ErrorMessage | Wherever X-Refract-ErrorCode is | One line of plain ASCII, at most 300 characters, in the Dispatcher's own wording. It never carries a path, a payload value, or the text of the underlying error. |
X-Refract-ErrorReportPath | Answers whose error report was stored | Where the stored error report is. Absent when it was not stored; the PDF in the body is then the only copy. |
X-Refract-LifecycleErrorCode and X-Refract-LifecycleError | An eSign, Delivery, or workflow step refused after the document was rendered and stored | The refused step's code and reason. |
X-Refract-CorrelationId | Every answer | The correlation ID. |
X-RateLimit-Limit, X-RateLimit-Window-Seconds, and X-RateLimit-Reset | The 429 rate limit of the connector routes | The limit, its window, and when it resets (Unix seconds). |
On a failed answer to /api/render, Access-Control-Expose-Headers lists these headers so that browser code on another origin can read them. Errors on the API overview describes the render answers in more detail.
When to Retry
- Retry only when
retryableistrue. These answers say that nothing was done and the same request can succeed later. Every one of them carriesRetry-After. - Honour
Retry-After. Wait at least that many seconds before the next try. Stop after a few tries and report the correlation ID. - Never retry a
4xx. The same request gets the same answer; fix what the code names. The one exception is429TOO_MANY_REQUESTSfrom the connector routes, a rate limit: wait forRetry-After, then send again. The monthly limits (DOCUMENT_QUOTA_EXCEEDED,monthly_hard_cap_reached, and the others under Licence and limits) are also429, and are not retried. - Do not resend a
5xxwithout"retryable": trueautomatically. Some of these carryRetry-Afterand say inmessagethat a later try may work; a person may resubmit after that wait. Keep the correlation ID and, for a PDF body, the error report.
async function callDispatcher(url, init, maxTries = 3) {
for (let attempt = 1; ; attempt++) {
const res = await fetch(url, init);
if (res.ok) return res;
const isJson = (res.headers.get('Content-Type') ?? '').includes('application/json');
const body = isJson ? await res.json() : null;
const code = body?.code ?? res.headers.get('X-Refract-ErrorCode');
const retryAfter = Number(res.headers.get('Retry-After') ?? 0);
const rateLimited = res.status === 429 && code === 'TOO_MANY_REQUESTS';
if ((body?.retryable === true || rateLimited) && attempt < maxTries) {
await new Promise((r) => setTimeout(r, Math.max(retryAfter, 1) * 1000));
continue;
}
const correlationId = res.headers.get('X-Refract-CorrelationId');
throw Object.assign(new Error(body?.message ?? `HTTP ${res.status}`), { status: res.status, code, correlationId });
}
}Power Automate retries on its own
An action's default retry policy in Power Automate resends 408, 429, and 5xx answers. For Generate Document, a resent 500 renders and stores the document again. Set the action's retry policy to None and handle the failure in the flow, as Handling Errors in a Flow shows.
Codes by Area
Status is the HTTP status; a code with more than one lists each. PDF means the body is an error-report PDF and the code is in X-Refract-ErrorCode. After render means the document was rendered and stored before the step was refused, and the code is also in X-Refract-LifecycleErrorCode. Retryable is Yes when the body says "retryable": true, No (false) when the body says "retryable": false, and No when the body has no retryable field. Retry-After is the header's value in seconds.
Licence and limits
| Code | Status | Retryable | Retry-After | Meaning | What to do |
|---|---|---|---|---|---|
LICENSE_UNAVAILABLE | 503 | Yes | 30 | The licence could not be checked: the licensing service did not answer, or answered with a server error, and this instance has no grace period. Nothing was done. | Send the same request again after Retry-After. If it keeps happening, ask your administrator to check that the Dispatcher can reach the licensing service. |
LICENSE_INVALID | 403 | No | - | The licence was checked and is not valid for this deployment: denied, expired, or not configured, or the licensing service's answer did not verify against its seal (the Dispatcher uses no answer it cannot verify). Every route that checks the licence answers it, the batch decision, template validation and the licence features routes included. | Do not retry. Ask your administrator to renew or configure the licence. |
FEATURE_NOT_LICENSED | 403 | No | - | The licence is valid but does not include a feature the request asked for. feature names it (for example vaultESign, vaultDelivery, vaultWorkflow, vaultDispatch, section508Accessibility). | Remove the feature from the request or the template, or add it to the licence. |
API_ACCESS_NOT_LICENSED | 403 | No | - | The licence turns API access off. | Ask your administrator to change the plan. |
DOCUMENT_QUOTA_EXCEEDED | 429 | No (false) | - | The plan's monthly document limit has been reached. | Do not retry this month. Wait for the next billing period, or change the plan. |
FILE_SIZE_LIMIT_EXCEEDED | 413 | No | - | The rendered PDF is larger than the plan's file size limit, or than the platform maximum of 100 MB that holds on every plan. Nothing was stored, sent, or counted. | Make the document smaller, or change the plan. Over the platform maximum, split the document. |
QUOTA_CHECK_UNAVAILABLE | 503 | Yes | 10 | The document, eSign or Delivery usage count could not be read, so the request was refused rather than served unchecked. Nothing was done. | Send the same request again after Retry-After. If it keeps happening, give the correlation ID to your administrator. |
LICENSE_ALLOWANCE_UNKNOWN | 503 | Yes | 30 | The licence answer carried no allowance for the eSign or Delivery sessions this request would create, so it was refused rather than served unchecked. Nothing was done. The answer names the allowance. | Send the same request again after Retry-After. If it keeps happening, ask your administrator to check that the Dispatcher can reach the licensing service. |
monthly_hard_cap_reached | 429 | No (false) | - | Sending or capturing would take this month's eSign or Delivery sessions past the licence's allowance. The answer names the allowance, how many are used, the limit, how many were requested and resetsAt, when the month's count starts again (UTC). | Do not retry before resetsAt. Send to fewer signers or recipients, or ask your administrator to upgrade the plan (or add the eSign add-on). |
overage_not_allowed | 429 | No (false) | - | Sending or capturing would take this month's eSign count past the allowance, and overage is turned off. | Do not retry. Remove a signer, or ask your administrator to allow overage. |
sms_hard_cap_reached | 429 | No (false) | - | The text messages this send needs would take this month's SMS count past the hard cap. | Do not retry. Ask your administrator to raise the limit. |
sms_overage_not_allowed | 429 | No (false) | - | The text messages this send needs would take this month's SMS count past the allowance, and SMS overage is turned off. | Do not retry. Wait for next month, or ask your administrator to allow overage. |
Render and storage
| Code | Status | Retryable | Retry-After | Meaning | What to do |
|---|---|---|---|---|---|
TEMPLATE_NOT_FOUND | 404 | No | - | The template is in neither the templates library nor the system templates library. | Fix templatePath, or upload the template. |
TEMPLATE_UNREADABLE | 422 | No | - | The template file is not JSON, or is JSON that is not an object. | Export the template again from the Designer and upload it. |
TEMPLATE_LAYOUT_SCHEMA_MISSING | 422 | No | - | The stored template has no layoutSchema. | Export the template again from the Designer and upload it. |
PAYLOAD_NOT_FOUND | 404 | No | - | The payload file is not in the payloads library. | Fix payloadPath, or upload the payload. |
PAYLOAD_UNREADABLE | 422 | No | - | The payload file is not JSON, or is JSON that is neither an object nor an array. | Fix the payload file. |
PAYLOAD_PATH_REQUIRED | 400 | No | - | The request has a templatePath and no payloadPath. | Send both templatePath and payloadPath. |
PATH_TRAVERSAL_REFUSED | 400 | No | - | templatePath or payloadPath contains a .. segment, a drive letter, or a network share prefix. | Use paths relative to the library. |
TEMPLATE_ID_UNKNOWN | 404 | No | - | No installed template has the templateId in the request. | Use the templateId of an installed template. |
RENDER_TEMPLATE_ID_REQUIRED | 400 | No | - | A render by templateId left out the templateId. | Send templateId, or render by templatePath and payloadPath. |
RENDER_JSON_DATA_REQUIRED | 400 | No | - | A render by templateId left out jsonData. | Send jsonData. |
DIRECT_JSON_DATA_REQUIRED | 400 | No | - | A direct render left out jsonData (the full payload, or a data record with a template). | Send jsonData. |
DIRECT_LAYOUT_SCHEMA_MISSING | 400 | No | - | A direct render's payload has no layoutSchema. | Provide a Designer-exported layoutSchema. |
DIRECT_DATA_MISSING | 400 | No | - | A direct render's payload has none of dataSource, sampleData, or data. | Add data to the payload. |
DIRECT_TEMPLATE_UNRESOLVED | 400 | No | - | A direct render's payload does not resolve to a template. | Fix the template or layoutSchema in the payload. |
DIRECT_TEMPLATE_SHAPE_INVALID | 400 | No | - | A direct render's template is a raw layoutSchema tree, not a resolved document definition. | Put the layoutSchema in jsonData instead. |
REDACTION_POLICY_NOT_FOUND | 422 | No | - | The redaction policy named in the template settings is not there. Strict redaction mode only; in soft mode the render continues without redaction. | Fix the policy path in the template, or upload the policy. |
REDACTION_POLICY_INVALID | 422 | No | - | The redaction policy named in the template settings does not parse as a valid policy. Strict redaction mode only. | Fix the redaction policy file. |
RENDER_FAILED | 500 (PDF) | No | - | The document could not be produced for a reason of the service's own: storage that cannot be reached, a throttle that outlasted the retries, or an error the Dispatcher did not expect. If the error report itself cannot be rendered, the body is JSON with this code. | Not marked retryable. Keep the correlation ID and the error report for your administrator. |
GENERATED_DOCUMENT_NOT_STORED | 503 500 (PDF) | 503: Yes 500: No | 503: 30 500: - | The request asked for the document to be stored, the document rendered, and nothing was stored, so it was not delivered. 503: the upload failed and a later try can store it. 500: document storage is not set up to store it, and every try fails the same way. | 503: send the request again after Retry-After. 500: do not retry; your administrator must fix document storage. |
GENERATED_DOCUMENTS_STORAGE_DISABLED | 422 | No | - | eSign or Delivery would run, but storage of generated documents is turned off, so the document could not be read back for signing or delivery. | Turn on generated document storage on a blob route, or turn eSign or Delivery off for this render. |
GENERATED_DOCUMENTS_ROUTED_TO_SHAREPOINT | 422 | No | - | eSign or Delivery would run, but generated documents are stored in SharePoint, which eSign and Delivery cannot read back. | Route generated documents to blob storage, or turn eSign or Delivery off for this render. |
ROUTING_TEMPORARILY_UNAVAILABLE | 503 | Yes | 30 | The storage routing configuration could not be read just now, and no earlier copy is known. Nothing was done. | Send the same request again after Retry-After. |
ROUTING_CONFIG_UNBUILDABLE | 503 | No (false) | - | The storage routing configuration was read but its routes cannot be built, for example a blob route with no storage account configured. | Do not retry. Your administrator must fix the storage configuration. |
DOCUMENT_ACCESS_ROW_UNWRITABLE | 500 (PDF) | No | - | The document was stored, but the record that controls who may open it could not be written, so it was not delivered. Batch documents report it in documents[].error. | Not marked retryable. The message asks you to submit the request again; if it repeats, give the correlation ID to your administrator. |
AUDIT_LOG_NOT_CONFIGURED | 503 | No | - | Audit logging is on, but no audit log destination is configured. Also reported on a successful render as X-Refract-AuditStatus: failed:AUDIT_LOG_NOT_CONFIGURED when the audit write did not happen. | Do not retry. Your administrator must configure the audit log destination. |
AUDIT_TIER_WITHDRAWN | 503 | No | - | The storage configuration routes audit logs to the withdrawn enterprise tier. | Do not retry. Your administrator must set audit logs to blob or basic. |
RENDERED_PAYLOAD_CHECK_UNAVAILABLE | 503 | Yes | 10 | The check of who may re-render a stored payload could not be made, so the render was refused. | Send the same request again after Retry-After. |
Accessibility
| Code | Status | Retryable | Retry-After | Meaning | What to do |
|---|---|---|---|---|---|
ACCESSIBILITY_CHECK_FAILED | 422 | No | - | The template blocks on an accessibility failure (it declares PDF/UA, or sets onFailure to block) and the document failed its Section 508 checks. It was not stored, sent, or counted. failedStandards names the standards. Validate and preview reports the same code in X-Accessibility-Refusal-Code, and batch documents in documents[].error. | Do not retry unchanged. Validate the template to see the findings, then fix the template or the data. |
ACCESSIBILITY_NOT_ASSESSED | 422 | No | - | The template blocks on an accessibility failure and the checks could not give a result for this document. | Do not retry unchanged. Check that the licence includes section508Accessibility, then ask your administrator. |
ACCESSIBILITY_ENHANCEMENT_FAILED | 422 | No | - | The accessibility enhancement pass failed for a template that blocks on an accessibility failure. Nothing was stored or delivered. | Give the correlation ID to your administrator. |
SECTION508_SETTING_REFUSED | 400 | No | - | A section508Accessibility setting cannot be used: a removed setting set to true, an onFailure that is not flag or block, flag beside level pdf-ua, or a request that would turn off or lower a blocking template's checks. setting names it. | Remove or fix the setting. |
PDF_UA_XMP_DECLINEDAvailable after the next release | 400 | No | - | The template declares PDF/UA (section508Accessibility level pdf-ua) and the request sets features.xmpMetadata to false. A PDF/UA document must carry XMP metadata, so it could only fail its checks. Refused before rendering, on direct and queued renders; nothing was rendered, stored or counted. setting is features.xmpMetadata. | Remove features.xmpMetadata from the request, or set it to true. |
Workflow
| Code | Status | Retryable | Retry-After | Meaning | What to do |
|---|---|---|---|---|---|
otp_setting_not_request_settable | 400 | No | - | The request sets templateSettings.workflow.requireOtp. Only the template can set it. | Remove requireOtp from the request and set it in the template. |
schema_path_not_request_settable | 400 | No | - | The request sets templateSettings.workflow.schemaPath. Only the template can set it. | Remove schemaPath from the request and set it in the template. |
WORKFLOW_INVITE_EXPIRY_INVALID | 400 422 (PDF, after render) | No | - | The workflow link life (expiresInDays) is not a number above 0 and at most 1. 422: found only after the document was rendered and stored; no workflow was created. | Set expiresInDays in range, or leave it out. |
WORKFLOW_REMINDERS_INVALID | 400 422 (PDF, after render) | No | - | The workflow reminders settings do not validate. | Fix templateSettings.workflow.reminders. |
WORKFLOW_POST_SEAL_SIGNING_UNSUPPORTED | 422 | No | - | The settings turn on both a workflow and eSign, which would ask for the sealed workflow document to be signed. | Turn off eSign or the workflow for this request. |
WORKFLOW_INITIAL_DATA_INVALID | 422 | No | - | A seeded value for a workflow date field is not a real date. fieldErrors lists them. From a render, the document is already stored and no workflow was created. | Correct the listed fields. |
WORKFLOW_ROUTING_INVALID | 422 | No | - | The workflow schema's approval.routing is malformed. problems lists what is wrong. | Fix approval.routing in the workflow schema. |
WORKFLOW_NO_DECIDER | 422 | No | - | Nobody could be chosen to approve: the schema has no routing and no workflow administrator is configured, or no route matches the data and there is no fallback. | Add routing or a fallback to the schema, or ask your administrator to configure a workflow administrator. |
WORKFLOW_OTP_NO_ADDRESS | 422 | No | - | The workflow requires a one-time code, but no recipient is named and the caller has no email address the code could go to. | Name a recipient in templateSettings.workflow.recipients, or set requireOtp: false in the template. |
WORKFLOW_TEMPLATE_UNREADABLE | 503 | Yes | 10 | The template could not be read: to find its workflow settings when a workflow is created, or to check an escalation address against its approver rules. Nothing was created or escalated. | Send the same request again after Retry-After. If it keeps happening, ask your administrator. |
APP_CANNOT_DECIDE | 403 | No | - | An app token called a workflow decision route. Only a signed-in person can approve, reject, request changes, or escalate. | Do not retry with an app token. A person must make the decision. |
WORKFLOW_STATE_CHANGED | 409 | No | - | The workflow changed while the decision was being written. state names the state it is in now. | Reload the workflow and decide again if the decision still applies. |
WORKFLOW_UNROUTED_ADMINISTRATOR_ONLY | 403 | No | - | The workflow has no readable routing, so only the configured workflow administrator can decide it. | Ask the workflow administrator to decide it. |
WORKFLOW_ESCALATION_NOT_PERMITTED | 403 | No | - | Only the approver assigned to the stage awaiting a decision, or the tenant's workflow administrator, can escalate a workflow. The caller is neither, or their sign-in carries no email address. | Do not retry. Ask the assigned approver or the workflow administrator to escalate it. |
WORKFLOW_ESCALATION_TARGET_NOT_PERMITTED | 403 | No | - | A workflow can be escalated only to an address its template's approver rules name (a route's approver or contact address, or the fallback approver) or to the tenant's workflow administrator. escalateTo is none of these. Nothing was escalated. | Escalate to an approver the template names, or to the workflow administrator. |
WORKFLOW_LINK_NOT_REGISTERED | 502 | No | - | The signing portal refused to register the participant's link, or this Dispatcher has no portal settings, so there is no link to send. reason says which; portalStatus is the portal's answer when there was one. A portal that could not be reached, timed out or failed (5xx) does not answer this: a create answers WORKFLOW_LINK_UNAVAILABLE, and any other send is held and retried. | Ask your administrator to check the Dispatcher's portal settings, then send again. |
WORKFLOW_LINK_UNAVAILABLE | 503 503 (PDF, after render) | 503: Yes 503: No | 60 | The signing portal could not register the first participant's link just now: it could not be reached, timed out, failed (5xx) or answered without a reference. The workflow was not created, and nothing was written or sent. A render that creates a workflow answers it the same way and stores no intake receipt. reason says which; portalStatus is the portal's answer when there was one. | Send the same request again after Retry-After. If it keeps happening, ask your administrator to check that the signing portal is reachable from the Dispatcher. |
WORKFLOW_ALREADY_CANCELLED | 409 | No | - | The workflow is already cancelled. | Nothing to do. |
WORKFLOW_NOT_CANCELLABLE | 409 | No | - | The workflow is past the approval decision (for example approved, sealing, complete, or rejected) and cannot be cancelled or declined. | Do not retry. |
eSign
| Code | Status | Retryable | Retry-After | Meaning | What to do |
|---|---|---|---|---|---|
ESIGN_REMINDERS_INVALID | 400 500 (PDF, after render) | No | - | The eSign reminders settings do not validate. | Fix the reminders settings. |
ESIGN_CC_RECIPIENTS_INVALID | 400 500 (PDF, after render) | No | - | The eSign ccRecipients list is not a list of up to 5 entries of { name, email } with a name and an address. | Fix the list. An entry that names a signer, the requester or an earlier entry is not refused: it is dropped, and the answer names it in ccDropped. |
ESIGN_DOWNLOAD_LINK_INVALID | 400 500 (PDF, after render) | No | - | The eSign download settings do not validate: download is not an object, expiresInDays is not a whole number of days from 1 to 30, or requireCode is not true or false. The body's source says whether the template's settings or the request's are wrong. | Fix the download settings, or leave them out for a seven-day link. A request longer than the template's link is not refused: the template's days apply. |
ESIGN_WINDOW_INVALID | 400 500 (PDF, after render) | No | - | The signing window (expiresInMinutes) is not a whole number from 60 to 10080. | Send a window in range, or leave it out. |
ESIGN_SESSION_FAILED | 500 (PDF, after render) | No | - | The document was rendered and stored, but the signing session could not be created for a reason of the service's own. | Not marked retryable. Give the correlation ID to your administrator. The document already exists, so a new render stores a second one. |
TEMPLATE_ROLES_UNVERIFIABLE | 400 500 (PDF, after render) | No | - | A signature block asset the template uses could not be loaded, so its signer roles cannot be checked. | Fix the template's signature block assets. |
TEMPLATE_ROLE_DISAGREEMENT | 400 500 (PDF, after render) | No | - | The template's schema names signer roles that its signatories do not declare. | Fix the template. |
TEMPLATE_HAS_NO_SIGNATURE_ANCHORS | 400 500 (PDF, after render) | No | - | The template declares no signature roles. | Add a signature block with named signatories to the template. |
SIGNER_ROLE_NOT_IN_TEMPLATE | 400 500 (PDF, after render) | No | - | A requested signer's role is not one the template declares. | Use the roles the template declares. |
REQUIRED_ZONE_NOT_REQUESTED | 400 500 (PDF, after render) | No | - | A required signature zone in the template has no requested signer. | Add a signer for every required role. |
SLOT_PREVIEW_NOT_MINTED | 503 500 (PDF, after render) | 503: Yes 500: No | 503: 10 500: - | A signer's document link could not be created, so nothing was sent. | 503: send the request again after Retry-After. 500: give the correlation ID to your administrator. |
DOCUMENT_NOT_BLOB_ROUTED | 422 500 (PDF, after render) | No | - | The document is stored in SharePoint, not blob storage, so eSign, Delivery, or document access cannot read it. | Route generated documents to blob storage and render again. |
DOCUMENT_BINDING_UNAVAILABLE | 503 | Yes | 5 | No render record exists yet for the correlationId. | Send the same request again after Retry-After. If the document was only just generated its record may still be on its way; if it keeps happening, the document was not rendered with eSign enabled. |
DOCUMENT_BINDING_LOOKUP_FAILED | 503 | Yes | 10 | The render record for the correlationId could not be read. Nothing was done. | Send the same request again after Retry-After. |
DOCUMENT_BINDING_AMBIGUOUS | 409 | No | - | More than one render record exists for the correlationId. | Do not retry. Render the document again and use the new correlation ID. |
DOCUMENT_BINDING_INCOMPLETE | 409 | No | - | The render record has no stored document path or no valid hash. | Do not retry. Render the document again. |
DOCUMENT_BINDING_MISMATCH | 409 | No | - | The pdfBlobPath or pdfHash in the request does not match the render record (a signing request, or a manual delivery send: its pdfBlobPath against the record its correlationId names). | Reload the document (it may have been rendered again) and resend, or leave out pdfBlobPath and pdfHash. |
DUPLICATE_ENVELOPE | 409 | No | - | Another signing request for this document is open or finished. | Wait for it to finish or revoke it before sending again. A sealed one blocks for good. |
DOCUMENT_ALREADY_SEALED | 409 | No | - | The document has already been sealed. | Render the document again to collect a new signature. |
NO_IMMUTABLE_AUDIT_ARCHIVE | 422 | No | - | The document was rendered without an immutable audit archive, which signing needs. | Turn on immutableAudit and render again. |
SEALED_WORKFLOW_NOT_SIGNABLE | 422 | No | - | The document belongs to a sealed workflow and cannot be sent for signature. | Do not retry. |
SEALED_WORKFLOW_CHECK_UNAVAILABLE | 503 | Yes | 10 | Whether the document belongs to a sealed workflow could not be checked. Nothing was done. | Send the same request again after Retry-After. |
SEAL_STATE_UNAVAILABLE | 503 | Yes | 10 | The document's evidence chain could not be read to check whether it is sealed. Nothing was done. | Send the same request again after Retry-After. |
SESSION_BINDING_NOT_RECORDED | 503 | Yes | 10 | The signing request's first evidence line could not be written, so nothing was sent. | Send the same request again after Retry-After. |
CAPTURE_BINDING_NOT_RECORDED | 503 | Yes | 10 | The captured signature's evidence line could not be written. | Send the same request again after Retry-After. The same captureId is not recorded twice. |
CONSENT_NOT_PRESENTED_NOT_RECORDED | 503 | Yes | 10 | The capture was recorded, but the line saying no consent policy was presented could not be written. | Send the same capture again after Retry-After to finish it. |
GROUP_EXPIRED | 409 | No | - | The signing request is past its deadline, so there is nothing to revoke. | Nothing to do. |
OPERATION_RESULT_MISSING | 404 | No | - | The result of a verify or reproduce operation is missing or empty. | Run the operation again. |
Consent
| Code | Status | Retryable | Retry-After | Meaning | What to do |
|---|---|---|---|---|---|
consent_not_request_settable | 400 | No | - | The request sets consent in templateSettings.esign, templateSettings.workflow or templateSettings.delivery. Whether a recipient is shown a consent policy, and which one, is chosen by the template. | Remove consent from the request, and set it in the template. |
consent_setting_retired | 400 500 (PDF, after render) | No | - | assetConsentPath is retired and is not read. A request that sets it is refused before anything is done (400); a template that still carries it is refused when it is used. A consent policy is named by templateSettings.<block>.consent.policyId in the template. | Remove assetConsentPath from the request and the template, and name the policy with consent.policyId in the template. |
consent_setting_invalid | 400 500 (PDF, after render) | No | - | The template's consent block is not valid: mode is not required or none, or policyId or a contact value is malformed. setting names the value. | Fix the consent block in the template. |
consent_mode_not_allowed | 400 500 (PDF, after render) | No | - | The template sets templateSettings.esign.consent.mode to none. A signer is always shown the consent policy. | Remove the consent block, or set mode to required. |
consent_requires_portal_link | 400 500 (PDF, after render) | No | - | The template sets templateSettings.delivery.consent.mode to required with a delivery mode (SHAREPOINT or BOTH) that hands the recipient the document without a portal link, so no consent step can be shown. | Use delivery mode SECURE_LINK, or set consent.mode to none. |
consent_path_invalid | 400 500 (PDF, after render) | No | - | The template's retired assetConsentPath is not a valid consent policy path. assetConsentPath is refused wherever it appears: a template or a request that sets it is answered consent_setting_retired, whatever its value. | Remove assetConsentPath from the template, and name the policy with consent.policyId (see consent_setting_retired). |
consent_policy_unreadable | 400 500 (PDF, after render) | No | - | The consent policy file could not be read. | Upload the consent policy file, or fix the path. |
consent_policy_invalid | 400 500 (PDF, after render) | No | - | The consent policy file does not parse as a valid policy. | Fix the consent policy file. |
consent_system_policy_unverified | 400 500 (PDF, after render) | No | - | No consent policy is named, and the built-in policy could not be verified. | Contact support. |
consent_template_mismatch | 409 | No | - | The templatePath in the request is not the template the document was rendered with. | Leave out templatePath, or send the path the document was rendered with. |
consent_template_unreadable | 400 500 (PDF, after render) | No | - | The template the document was rendered with could not be loaded to find its consent settings (a signing request, or a manual delivery send of a document with a render record). | Restore the template and render again. |
consent_capture_not_recorded | 503 500 (PDF, after render) | 503: Yes 500: No | 503: 10 500: - | The consent policy could not be stored for the signing request. Nothing was sent. | 503: send the request again after Retry-After. 500: give the correlation ID to your administrator. |
consent_layer_unavailable | 503 500 (PDF, after render) | 503: Yes 500: No | 503: 30 500: - | This deployment requires a consent step, or the template requires one for a delivery, and the signing portal cannot show it (a delivery needs the portal to list deliveryConsent). Nothing was sent. A queued delivery records it as DELIVERY_SKIPPED instead. | Send the request again after Retry-After. If it keeps happening, ask your administrator to check the signing portal's version. |
Delivery and batch
| Code | Status | Retryable | Retry-After | Meaning | What to do |
|---|---|---|---|---|---|
DELIVERY_EXPIRY_INVALID | 400 422 (PDF, after render) | No | - | The delivery link life is out of range (above 0, at most 30 days). 422: a workflow's post-seal delivery, found after the document was rendered and stored. | Set the expiry in range, or leave it out. |
DELIVERY_REMINDERS_INVALID | 400 | No | - | The delivery reminders settings do not validate. | Fix the reminders settings. |
BATCH_TOO_LARGE | 400 | No | - | The batch has more records than the batch limit. | Split the batch. |
BATCH_RECORD_TOO_LARGE | 400 | No | - | A batch record is larger than the store accepts. | Shrink the record. |
DECISION_COMMENTS_TOO_LONG | 400 | No | - | A batch decision's comments are longer than 1,000 characters. Nothing was changed. | Shorten the comments and decide again. |
DELIVERY_NOT_FOUND | 404 | No | - | No delivery with that ID exists in your tenant. A delivery in another tenant gets the same answer. | Check the delivery ID. |
DELIVERY_LINK_NOT_REGISTERED | 502 | No | - | A send that emails links was refused because the signing portal refused to register a recipient's link (a 4xx), or this Dispatcher has no portal settings or no routing envelope, so there is no link it could send. reason says which; portalStatus is the portal's answer when there was one. Nothing was written or sent, for any recipient. Not retryable as it stands: a portal that could not be reached, timed out or failed (5xx) does not answer this; the send is accepted, the recipient's invitation is held and retried, and its session says held: true with no portalUrl. | Ask your administrator to check the Dispatcher's portal settings, then send again. |
Authentication and access
| Code | Status | Retryable | Retry-After | Meaning | What to do |
|---|---|---|---|---|---|
TOKEN_MISSING | 401 | No | - | The request has no bearer token. | Send an access token for the REFRACT Dispatcher API. |
TOKEN_INVALID | 401 400 | No | - | 401: the bearer token failed its signature, issuer, audience, or expiry check. 400 (signing portal only): a link token does not verify. | Get a new token for the REFRACT Dispatcher API. |
TENANT_SCOPE_NOT_CONFIGURED | 503 | No | - | The Dispatcher has no AZURE_TENANT_ID setting, so no token can be checked. | Do not retry. Your administrator must set AZURE_TENANT_ID. |
TENANT_ID_MISSING | 403 | No | - | The token has no tid claim. | Use a token issued by the Dispatcher's tenant. |
TENANT_ID_MISMATCH | 403 | No | - | The token was issued by another tenant. | Use a token issued by the Dispatcher's tenant. |
SCOPE_MISSING | 403 | No | - | A signed-in user's token does not carry the user_impersonation scope. | Grant and consent the delegated user_impersonation permission, then sign in again. |
ROLE_MISSING | 403 | No | - | The caller does not hold the role the route needs. role names it: Render.Access for an app token, or Lifecycle.Reader for reading document and workflow records. | Assign the role named in role, grant admin consent, and get a new token. |
ASSERTION_ALLOWLIST_NOT_CONFIGURED | 503 | No | - | No app is allowed to request document access assertions on this deployment. | Do not retry. Your administrator must configure the allowed apps. |
ASSERTION_SOURCE_APP_MISMATCH | 403 | No | - | The document was produced by another app or by a person; only the app that produced it may request an assertion. | Do not retry. |
ASSERTION_SOURCE_APP_UNRECORDED | 403 | No | - | The document's access record does not name the app that produced it, so no app may request an assertion. | Do not retry. |
Requests
| Code | Status | Retryable | Retry-After | Meaning | What to do |
|---|---|---|---|---|---|
INVALID_JSON_BODY | 400 | No | - | The request body is not JSON. | Fix the request body. |
INVALID_REQUEST_BODY | 400 | No | - | The request body is JSON but a required field is missing or has the wrong type. | Fix the request body. |
IDEMPOTENCY_KEY_INVALID | 400 | No | - | The idempotency key is empty, longer than 256 characters, or contains /, \, #, ?, or a control character. | Send a valid key, or leave it out. |
REQUEST_BODY_TOO_LARGE | 413 | No | - | The request body is larger than 20 MB. | Send a smaller body. |
BAD_REQUEST | 400 | No | - | A 400 whose route names no code of its own. | Read message and fix the request. |
UNAUTHORIZED | 401 | No | - | A 401 whose route names no code of its own. | Get a new token. |
FORBIDDEN | 403 | No | - | A 403 whose route names no code of its own: for example a container that is not allowed, a document access policy that refuses the caller, or an invalid licence on batch decide and licence features. | Read message or detail. |
NOT_FOUND | 404 | No | - | A 404 whose route names no code of its own: a workflow, operation, audit record, or document that is not there. | Check the ID. |
METHOD_NOT_ALLOWED | 405 | No | - | A 405 whose route names no code of its own. | Use the method the route accepts. |
CONFLICT | 409 | No | - | A 409 whose route names no code of its own: the record is not in a state that allows the request. | Read message, reload the record, and decide again. |
GONE | 410 | No | - | A 410 whose route names no code of its own. | Do not retry. |
PAYLOAD_TOO_LARGE | 413 | No | - | A 413 whose route names no code of its own. | Send a smaller body. |
UNSUPPORTED_MEDIA_TYPE | 415 | No | - | A 415 whose route names no code of its own. | Send a supported content type. |
UNPROCESSABLE | 422 | No | - | A 422 whose route names no code of its own. | Read message and fix the request. |
TOO_MANY_REQUESTS | 429 | Yes | Seconds to reset | The rate limit of the connector routes (/api/gateway/v1/...): more than 100 requests in 60 seconds from one tenant and app. It carries retryable: true, and Retry-After is the seconds until the window resets. Also the code filled in for any other 429 that names none. | Wait for Retry-After, then send again. The one 4xx a caller may resend unchanged. A monthly limit is a 429 with retryable: false: do not resend it. |
SERVICE_UNAVAILABLE | 503 | With retryable: true: YesWithout retryable: No | With retryable: true: 10Without retryable: - | A 503 whose route names no code of its own. With retryable: true and Retry-After, a store or service did not answer and nothing was done. Without them it is a configuration problem: error: BLOB_STORAGE_NOT_CONFIGURED means blob storage or the audit key is not configured. | With retryable: true, send the same request again after Retry-After. Without it, do not retry: read error, and ask your administrator. |
capability_unavailableAvailable after the next release | 503 500 (PDF, after render) | 503: Yes 500: No | 503: 30 500: - | A shared REFRACT service this request needs (the signing portal, the notification service or the licensing service) lacks a capability the request requires: an eSign envelope with CC recipients needs the CC notices, and a delivery that requires consent needs the decline notice to its sender. Nothing was created or sent. service names the service and capabilities what it lacks. An automatic signing session records it as LIFECYCLE_SETUP_REJECTED. A licence check the licensing service refuses for a missing capability is answered the same way (service licensing), never as an invalid licence and never from the grace period. | Send the same request again after Retry-After. It clears when the service is updated; if it keeps happening, give the correlation ID to your administrator. |
Next Steps
- REFRACT Dispatcher API - Endpoints, response headers, and how a failed render answers
- Authentication - Tokens, roles, and who may call
- Power Platform API Reference - The connector's actions and their error responses
- Power Platform Connector Setup - Connection setup and troubleshooting
Connect a source system
Which Microsoft Entra ID app registrations a REFRACT deployment creates, which ones you create, and how to connect Business Central, Dynamics 365 Sales, Dynamics GP, Power Platform, or your own scripts to the Dispatcher with a connector app per system.
Testing with Postman
Call the Dispatcher API from Postman with a testing app registration, either as an app (client credentials) or as a signed-in person (Authorization Code with PKCE).