Developers
API error codes
Every failure from the OPDC API for Sage 100 Contractor is a problem document (RFC 9457) whose type names one of these codes, which is also sent as the X-Error-Code header. Codes are append-only: a code's spelling and meaning never change once published. How errors work, and what to retry.
| Code | Status | Meaning |
|---|---|---|
| UNAUTHORIZED | 401 | Missing, malformed or unknown API key. |
| FORBIDDEN | 403 | The key authenticated but may not do what was asked: on a read, the request names a field this key may not read (sensitive, personal or pay data). |
| SERVICE_DISABLED | 503 | The key is switched off by Twinn. |
| MAINTENANCE_LOCK | 423 | The operator-held maintenance lock. |
| LOCK_CONFLICT | 409 | An unlock attempt against a lock another user holds. |
| REQUEST_INVALID | 400 | Unreadable or unparseable request body. |
| HEADER_INVALID | 400 | A correlation header that is present but not a UUID. |
| CHANGE_STAMP_UNSUPPORTED | 501 | lastUpdated or createdSince named on an entity that has no such column. |
| UPSTREAM_TIMEOUT | 504 | No reply from the on-premise service inside the window. |
| SCRIPT_NOT_FOUND | 500 | A route with no script in the store: a deployment fault, never the caller's. |
| RESPONSE_INVALID | 500 | A reply from the on-premise service that did not fit the expected envelope. |
| INTERNAL_ERROR | 500 | The default. |
| IDEMPOTENCY_KEY_REUSED | 409 | Same Idempotency-Key, different request: a different request fingerprint, or the same body on a different route. |
| IDEMPOTENCY_KEY_IN_FLIGHT | 409 | A request with this Idempotency-Key is still in progress. |
| IDEMPOTENCY_KEY_INVALID | 400 | Idempotency-Key empty, over 128 characters, or carrying non-printable characters. |
| PERIOD_CLOSED | 422 | The target period is beyond the ledger's current period, or outside the postable window. |
| PERIOD_UNRESOLVED | 422 | A posting date that could not be resolved to a period or year at all. |
| LEDGER_SETUP_MISSING | 422 | The ledger setup could not be read: the ledger is not set up, or the connected schema is not the intended one. |
| JOURNAL_UNBALANCED | 422 | Debits do not equal credits. |
| JOURNAL_EMPTY | 422 | A journal with no lines. |
| JOURNAL_LINE_INVALID | 422 | A line missing something structural, typically an account. |
| DUPLICATE_TRANSACTION | 409 | A transaction number already posted with different lines. |
| LEDGER_ACCOUNT_UNKNOWN | 422 | An account number that does not exist in the chart of accounts. |
| JOURNAL_ALREADY_VOID | 409 | The journal being voided is already void. |
| JOURNAL_NOT_VOIDABLE | 422 | The journal cannot be voided: it has cleared the bank, its status moved no balance, or it has no lines. |
| SUBACCOUNT_REQUIRED | 422 | A line on an account that tracks subaccounts or departments, sent with no subaccount, or with one that does not belong to that account. |
| REVERSAL_NOT_ALLOWED | 422 | A journal asked to reverse in the next period that cannot be: only a journal entry (source 3) posted Open can be reversed. |
| SUBCONTRACT_NOT_FOUND | 422 | No subcontract has the number an AP invoice names. |
| SUBCONTRACT_REFUSED | 422 | An AP invoice names a subcontract whose status is Refused. |
| SUBCONTRACT_MISMATCH | 422 | An AP invoice names a subcontract of another vendor, or on another job. |
| SUBCONTRACT_LINE_REQUIRED | 422 | A line of an AP invoice that bills a subcontract names no subcontract line. |
| SUBCONTRACT_LINE_NOT_FOUND | 422 | A line names a subcontract line that is not on the subcontract or has no line reference, or names one with no subcontract on the invoice. |
| CHANGE_NUMBER_REQUIRED | 422 | No change number was sent and the job's last one is not a number Sage's NEXT can increment. |
| REQUESTED_PRICE_MISMATCH | 422 | A prime line's requested price disagrees with the price its estimate and markups give. |
| SUBCONTRACT_NOT_OPEN | 422 | A change line names a subcontract that is not for the order's job and phase and the line's vendor, or is not status 3, 4 or 5. |
| CHANGE_ORDER_CLOSED | 409 | An update to a change order whose status is Void or Rejected, which Sage never saves again. |
| CHANGE_ORDER_LOCKED | 409 | An update to a change order locked for editing that does not unlock it. |
| CREDIT_CARD_INVALID | 422 | A credit card receipt names a card issuer that is not a card issuer account or is inactive, or a card that is not an active card of that issuer. |
| RECEIPT_EXCEEDS_ORDER | 422 | A purchase-order receipt that receives more than a line has left to receive (ordered, less already received and cancelled), or that names a line that is not on the purchase order. |
| RECEIPT_STATUS_NOT_ALLOWED | 422 | A purchase-order receipt against an order that is Void or a Master, or whose status the order cannot be left at. |
| INSUFFICIENT_INVENTORY | 422 | An inventory allocation that would take more of a part out of a location than is available there. |
| COST_LAYERS_SHORT | 422 | A document that takes more of a part out of stock than the part's cost layers hold. |
| TAX_LIMIT_TYPE_UNSUPPORTED | 422 | A tax entity of the document's tax district limits its tax across the job's, location's or client's earlier invoices, which is not supported yet. |
| TAX_EDITION_UNSUPPORTED | 422 | The company has Canadian sales tax set up, which is not supported yet. |
| DOCUMENT_POSTED | 409 | An update to a document that can no longer be changed in place: a purchase order that is closed, void or a master order. |
| DOCUMENT_CHANGED | 412 | An update whose If-Match is not the document's current version: it was changed, through this API or in Sage, after it was read. |
| QUANTITY_BELOW_RECEIVED | 422 | A purchase-order update that would order less on a line than the line has already received, or remove a line that has received anything. |
| INVOICE_NOT_OPEN | 422 | A cash receipt applied to an invoice that is not open: it is paid or void. |
| RECEIPT_EXCEEDS_BALANCE | 422 | A cash receipt that pays more than an invoice's balance, or takes more discount than the invoice has available. |
| SERVICE_INVOICE_NOT_POSTABLE | 422 | A service invoice whose totals or status do not permit a GL post. |
| PAYROLL_BATCH_EMPTY | 422 | A payroll batch carrying no checks. |
| PAYROLL_CHECK_INVALID | 422 | A check that failed the arithmetic or rate checks. |
| PAYROLL_EARNING_UNSUPPORTED | 422 | An earning whose payType is outside Sage's 1-9. |
| PAYROLL_DEDUCTION_INVALID | 422 | A deduction with no calculation number, which would post to the GL but not the subledger. |
| INVOICE_STATUS_NOT_ALLOWED | 422 | A new AP invoice at a status it cannot be entered at. |
| RETENTION_INVALID | 422 | An AP invoice's retention is negative, more than the invoice total, or set on a credit (a negative total). |
| INVOICE_AMOUNT_MISMATCH | 422 | An AP invoice sent an invoiceBalance or invoiceNet that is not the value the invoice computes: the balance is the invoice total and the net is the total less retention. |
| EQUIPMENT_COST_INVALID | 422 | An AP invoice line names equipmentNumber but cannot be costed to it: it has no accountNumber, its account is not an equipment expense account, it has no costCode, no cost type can be found for it, or the equipment is inactive. |
| ATTACHMENTS_DISABLED | 403 | File attachments are not turned on for this API key, or its setting could not be checked. |
| ATTACHMENTS_OFF_AT_SITE | 403 | The company's on-premise service has file attachments switched off. |
| ATTACHMENTS_UNAVAILABLE | 503 | File attachments cannot run just now. |
| ATTACHMENTS_NOT_ALLOWED_BY_SAGE | 422 | Sage's own file attachment settings do not allow a copied file for the record's module. |
| ATTACHMENT_EXPIRED | 410 | The file was gone when the on-premise service went to fetch it: a file is kept at most 30 minutes. |
| ATTACHMENT_CORRUPT | 502 | The file's size or SHA-256 did not match on its way between this API and the on-premise service. |
| RECORD_NOT_FOUND | 404 | A referenced record does not exist. |
| FIELD_REQUIRED | 400 | A required input field was absent or empty. |
| FIELD_INVALID | 400 | A field was present but its value does not satisfy the field's rule. |
| NOT_IMPLEMENTED | 501 | A route that exists but is deliberately not wired up. |
| INVOICE_NOT_PAYABLE | 422 | A payment names an invoice that cannot be paid: another vendor's invoice, one already paid or void, or one held for review or dispute. |
| PAYMENT_EXCEEDS_BALANCE | 422 | A payment's amount and discount on an invoice come to more than the invoice's payable balance: its net due, or its balance including held retention when the application sets includeRetention. |
| BANK_ACCOUNT_NOT_CASH | 422 | A payment drawn on a ledger account that is not a cash account. |
| VENDOR_CERTIFICATE_EXPIRED | 422 | A payment to a vendor with a stop-pay certificate that expired on or before the payment date, vendor-wide or for the job of an invoice being paid. |
| INVOICE_SET_TO_PAY | 409 | A payment names an invoice that a Sage user has staged for payment in Sage, so Sage's own next check run could pay it a second time. |
| SECOND_PAYEE_UNSUPPORTED | 422 | A payment names an invoice with a second payee (a two-party check). |
| CREDIT_NOT_APPLICABLE | 422 | A payment's credit row is not an open credit of the vendor, or its credits come to more than the invoices they offset. |
| PERIOD_BEFORE_INVOICE | 422 | An AP payment or a cash receipt posts to a period before the period of an invoice it pays. |
| DAILY_PAYROLL_LINE_INVALID | 422 | A daily payroll line Sage would refuse to save. |
| TIMECARDS_NOT_CREATED | 422 | Create Timecards was refused before anything was written. |
| VALIDATION_FAILED | 400 | Report criteria that do not satisfy the report's declared parameters. |
| REPORT_NOT_FOUND | 404 | A report id the catalogue does not list. |
| REPORT_ROW_LIMIT | 422 | The report read more rows than its row ceiling. |
| REPORT_RESULT_TOO_LARGE | 422 | The report's result is larger than a result may be. |
| SERVICE_CAPABILITY_MISSING | 501 | The on-premise agent for this company does not support what was asked, such as a report or a match lookup. |
| JOB_NOT_FOUND | 404 | A report job id this API does not hold: never issued, another customer's, or past its retention. |
| JOB_NOT_DONE | 409 | The job's result was requested before the job finished. |
| SAGE_SCHEMA_MISMATCH | 422 | A column or table the script expected and this Sage build does not have. |
| SAGE_FOREIGN_KEY_VIOLATION | 422 | A referenced record does not exist in Sage, or the write would orphan a child row: SQL Server Msg 547, a foreign key or reference constraint. |
| SAGE_DUPLICATE_KEY | 409 | The record already exists in Sage: Msg 2627 (a PRIMARY KEY or UNIQUE constraint) or Msg 2601 (a unique index). |
| SAGE_NOT_NULL_VIOLATION | 422 | A column this Sage build requires received no value: Msg 515, NOT NULL. |
| SAGE_RULE_VIOLATION | 422 | Sage's own enforcement refused the write. |
| SAGE_ERROR | 502 | Any other database-side failure: a deadlock, a permission, a dropped connection. |
| SCRIPT_FAILED | 500 | A script that failed in a way with no more specific code. |
| COMPANY_LOCKED | 423 | The company is not taking requests right now, and nothing was executed. |
| MESSAGE_TOO_LARGE | 413 | The request or its reply is larger than this API key allows. |
| QUEUE_UNAVAILABLE | 503 | The request could not be queued for the on-premise agent. |
| HOST_UPGRADE_REQUIRED | 503 | The company's on-premise agent speaks a protocol version older than this API supports. |
| KEY_STORE_UNAVAILABLE | 503 | The API key could not be checked just now. |
| KEY_WRONG_ENVIRONMENT | 401 | The API key was issued for a different environment (production, QA or local dev) than the API it was sent to. |
| REQUEST_EXPIRED | 503 | A write that could not start before its start-by deadline. |
| OUTCOME_UNKNOWN | 500 | The write may or may not have committed, and the service cannot tell which. |
| REQUEST_CANCELLED | 409 | The write was cancelled before it started. |
| REQUEST_ALREADY_COMPLETED | 409 | A cancel for a request that already has its outcome. |
| REQUEST_ALREADY_STARTED | 409 | A cancel for a write that had already started. |
| MCP_KEY_REFUSED | 403 | The API key is not an MCP connection key. |
| AUTHORIZATION_UNAVAILABLE | 503 | What this MCP connection may see could not be checked just now. |
| RATE_LIMITED | 429 | This API key sent more requests of this kind (reads, writes, report submissions or MCP calls) than its rate limit allows. |
| COMPANY_READ_ONLY | 403 | The company is set up read-only: Twinn reads its data and never changes it, so every write is refused. |
| UPSTREAM_UNAVAILABLE | 503 | The on-premise agent cannot reach the company's Sage database just now: it is waiting for the database server to answer, or it has stopped serving the company until the database or its sign-in is fixed. |