All error codes
Complete reference of every public API error code, grouped by bounded context, with its HTTP status and type.
This is the canonical reference of every error code the public API can return, grouped by the bounded context that emits it. Each code is stable across versions; the message is for display only. The total count and grouping are generated from the live catalog.
Account
| Code | Type | HTTP | Description |
|---|---|---|---|
access_level_raise_forbidden | invalid_request_error | 422 | Someone tried to raise the access level on a managed account whose holder has already claimed it. Since the claim only the holder can raise that level; the provider can only lower it. |
account_not_found | not_found_error | 404 | The account behind the key could not be resolved, which usually means the key no longer points at a live company. |
administrator_key_not_grantable | invalid_request_error | 422 | One of the sections in grants is an Administrator key (user management, plan and subscription, API and developers or digital certificate) and those sections are never granted to a member. |
api_key_already_revoked | invalid_request_error | 422 | The key was already revoked, and a revoked key admits no further operations: revocation is terminal. |
api_key_not_found | not_found_error | 404 | The identifier does not match any API key of the authenticated company. |
enterprise_contract_transition_required | invalid_request_error | 422 | The managed account has an enterprise contract and, on ending the management, its payment would move to the holder before Factuarea has set the plan it continues on. A subscription is never created without a price, so nothing was changed. |
external_advisor_already_assigned | invalid_request_error | 422 | The account already has an external advisor marked: there can only be one per account. |
grant_company_not_in_account | invalid_request_error | 422 | The grant's tax ID is not a real tax ID of the account, or it is outside the credential's tax ID scope. Both cases get the same answer, without telling which. |
grants_only_for_member | invalid_request_error | 422 | Only a member with the member role can hold per tax ID permissions (grants). The owner (owner) and the administrators (admin) reach every tax ID of the account, so a grant on them would mean nothing. |
import_file_invalid | invalid_request_error | 422 | One of the import files cannot be read with the template format: it is not a readable CSV, its header does not appear within its first 20 lines, it lacks a required column or it has a broken line. param says which file fails (accounts_file or customers_file) and the message names the column or the line. Nothing was written. |
import_file_too_large | invalid_request_error | 413 | One of the import files exceeds 5 MB. The size is checked before reading any row, so nothing was processed or written. param says which file fails (accounts_file or customers_file). |
import_in_progress | conflict_error | 409 | A bulk import of this provider account is already in progress. Imports of the same account are applied one at a time so that no account, charge or tax ID is created twice, so this one was not applied and nothing was written. |
import_row_limit_exceeded | invalid_request_error | 422 | One of the import files carries more rows than a single import accepts: 100 in the accounts file (accounts_file) and 1,000 in the customers file (customers_file). Rows are counted before being read, so nothing was processed or written. param says which file fails. |
invitation_expired | invalid_request_error | 422 | The invitation exists and belongs to this company, but its acceptance window already closed, so the person who received it can no longer redeem it. |
invitation_not_found | not_found_error | 404 | The identifier matches no pending invitation of the authenticated company: it may have been cancelled, already accepted, or issued by a different company. |
live_credential_required | authorization_error | 403 | A test key tried to change a live account. It only happens on the operations that change the account —members, invitations, ownership, tax ID transfers, NIF portfolio, keys and seats—: a test key cannot alter real data. |
managed_account_external_ref_in_other_environment | conflict_error | 409 | The external reference is already used by a managed account of the other environment (live or test). The reference is unique across both environments, and the answer does not name that account because this environment does not list it. Nothing was written. |
managed_account_not_claimable | invalid_request_error | 422 | The managed account is a test one, and a test account is never claimed: it has no claim voucher to issue or reissue. |
managed_account_plan_not_self_serve | invalid_request_error | 422 | The enterprise plan was requested for a managed account. A managed account is created or changed on emprendedor or empresario; enterprise is only assigned by Factuarea under contract. |
managed_account_provider_in_trial | invalid_request_error | 422 | The provider account is on its trial period and requested a live managed account, which is charged. During the trial only test managed accounts can be created. |
managed_accounts_limit_reached | invalid_request_error | 422 | The provider account already has as many live managed accounts under active management as its cap allows. Test managed accounts do not count towards that cap. |
member_is_last_owner | invalid_request_error | 422 | The operation would leave the NIF with nobody able to administer it: the member being removed, or demoted to a role without administration, is the last one holding the owner or admin role in that NIF. |
member_not_found | not_found_error | 404 | The identifier matches nobody on the account team: either that person was never a member of the authenticated company, or they belong to a different one. The account surface answers both cases alike. |
module_not_grantable | invalid_request_error | 422 | One of the sections in grants cannot be granted: it is not an administrator-only section (a member already reaches it with normal permissions) or the company does not have it in its plan. |
nif_transfer_expired | invalid_request_error | 422 | The tax ID transfer was genuinely issued, but its validity period ran out. Unlike an unrecognised transfer, this answer only reaches whoever already held a real one, so it reveals nothing new. |
nif_transfer_invalid | invalid_request_error | 422 | The tax ID transfer presented authorizes nothing: its secret is mistyped, truncated, already consumed, or was never issued. All of those answer alike on purpose, so the operation cannot be used to probe which transfers exist. |
owner_transfer_forbidden | authorization_error | 403 | The caller is not allowed to transfer ownership of the account: either they are not the current owner, or the proposed recipient cannot hold it. This is a matter of permission, not of a malformed payload. |
permissions_not_applicable_to_administrator | invalid_request_error | 422 | The member is an owner or admin of the account: they hold every permission of their plan and take neither restrictions nor section grants. |
permissions_not_applicable_to_employee | invalid_request_error | 422 | The person is an employee of the employee portal: their access is governed by the portal, not by the section matrix, so they take neither restrictions nor grants. |
plan_limit_exceeded | payment_required_error | 402 | The company has reached a resource limit for its plan. |
privileged_scope_required | authorization_error | 403 | The operation requires the account provider privilege (accounts:read or accounts:write) and it is not met: either the key's account has not been granted it, or the person who issued the key is no longer an owner or administrator of the account. Both causes answer alike. |
provisioning_account_claimed | conflict_error | 409 | The holder has already claimed this managed account and runs it on their own: it can no longer be claimed again, have its claim voucher reissued or be provisioned again with the same external reference. |
relation_already_exists | invalid_request_error | 422 | There is already a pending or active access between these two accounts, and only one can be open for each pair of accounts. |
relation_company_not_in_grantor | invalid_request_error | 422 | The list of tax IDs of the access is not valid: either it names a tax ID that does not belong to the account granting the access, or it is empty. The error points at the company_ids field and does not tell which tax ID fails. |
relation_invitation_expired | invalid_request_error | 422 | The access invitation exists and is still pending, but its acceptance window ran out, so it can no longer be accepted. |
relation_invitation_invalid | invalid_request_error | 422 | The access invitation presented is no good: its secret does not exist, was already used, was revoked or is addressed to another account. All of those answer alike on purpose, so the operation cannot be used to probe other accounts' invitations. |
relation_self_grant_not_allowed | invalid_request_error | 422 | The account given cannot receive the access: either it is the same account granting it, or the identifier does not match a valid account. Both cases answer alike. |
relation_transition_not_allowed | invalid_request_error | 422 | The access between accounts is in a state that does not admit the requested change: for example, accepting one that is already active or resending the invitation of one that has ended. |
sender_identity_not_verified | invalid_request_error | 422 | The sending company has not proven its identity yet, and without that it cannot write to external recipients from the shared sender domain. This is neither an exhausted quota nor a permission problem: the credential holds the scope, and waiting does not clear it. |
Authentication
| Code | Type | HTTP | Description |
|---|---|---|---|
api_key_expired | authentication_error | 401 | The key passed its expiry date. |
api_key_revoked | authentication_error | 401 | The key was revoked, and a revoked key never authenticates again — revocation is the way to cut off a leaked credential. |
invalid_api_key | authentication_error | 401 | The key does not match any active key. It may be mistyped, truncated, or belong to a different environment — test keys and live keys are not interchangeable. |
ip_not_allowed | authentication_error | 401 | The key restricts the addresses it accepts, and the request came from one outside that list. |
missing_api_key | authentication_error | 401 | The request carries no credentials: neither the Authorization header nor X-API-Key. |
origin_not_allowed | authentication_error | 401 | The request comes from a browser origin that the key does not accept. |
too_many_auth_failures | authentication_error | 429 | Too many failed authentication attempts arrived from the same address, so it is temporarily locked out to stop credential guessing. |
Authorization
| Code | Type | HTTP | Description |
|---|---|---|---|
addon_not_active | authorization_error | 403 | The functionality belongs to an add-on that is not active for the company right now. |
company_read_only | authorization_error | 403 | The person who issued the credential has read-only access (level view) to the effective company: their role in the account lets them see that tax ID, not write to it. The effective level is the lower of the one stored on the credential and the one the person holds today. |
emitter_capability_restricted | authorization_error | 403 | The person who issued the credential has the section or action required by the operation withdrawn in the effective company. It is the same per-module restriction the company administrator set for them in the web app, and it applies even if their access level to the tax ID is operate. |
feature_not_available_in_plan | authorization_error | 403 | The feature is not included in the company plan. |
forbidden_action | authorization_error | 403 | The action is refused even though the scope is right. The usual reasons are: your credential reaches the tax ID through an account relation (access granted to your account, or a managed account) and the operation belongs to the account that owns the tax ID — request logs, events, webhook endpoints, account billing, automation usage and writes of connected payment credentials are never available through a relation; the tax ID belongs to a managed account whose holder already pays for it, so its provider can read it and edit its data but can no longer activate, deactivate or archive it; the person who issued the credential is not an owner or admin of the account, or the credential does not reach every tax ID of the account; or the resource belongs to a shared catalogue, or the change travels through a different endpoint. |
insufficient_scope | authorization_error | 403 | The key authenticates correctly but does not carry the scope this operation requires. Scopes are granted when the key is issued and are not widened at call time. |
max_api_keys_exceeded | authorization_error | 422 | The company reached the number of API keys its plan allows. |
max_webhook_endpoints_exceeded | authorization_error | 422 | The company reached the number of webhook endpoints its add-on tier allows. |
module_not_available_in_sandbox | authorization_error | 403 | The resource belongs to a module vetoed in test mode. Sandbox never touches AEAT, banks or real billing, so those modules stay out on purpose. |
portfolio_max_api_keys_exceeded | authorization_error | 422 | The account already holds the maximum number of ACTIVE credentials that a portfolio allows. The cap applies once the account has two or more real tax IDs and is counted over all the active credentials of the account, not per tax ID, so adding another tax ID to mint its credential will not let you create this one either. |
scope_not_allowed_by_plan | authorization_error | 422 | One of the requested scopes belongs to a module that the plan does not include, so the key would be born with a permission that could never be exercised. |
scope_not_allowed_in_sandbox | authorization_error | 422 | A test key cannot be born with scopes of modules vetoed in sandbox. |
Automations
| Code | Type | HTTP | Description |
|---|---|---|---|
automation_action_order_invalid | invalid_request_error | 422 | The position of a step inside the sequence is not a whole number, or it is negative. That position is what fixes the order in which the actions run. |
automation_action_parameter_missing | invalid_request_error | 422 | A parameter the action declares as required did not arrive. It is rejected here, rather than filled in with a default inside the adapter, so that a dry run predicts the real execution. |
automation_action_parameter_unknown | invalid_request_error | 422 | A parameter key does not belong to the schema of the action. Accepting it would store a setting no adapter reads, and you would believe it active until the rule fired and did something else. |
automation_action_parameter_value_invalid | invalid_request_error | 422 | A parameter of the action carries a value outside the set its schema accepts. |
automation_action_parameters_invalid | invalid_request_error | 422 | The parameters of an action do not hold as a set: a value is not serialisable, a key is not text, two mutually exclusive parameters arrived together, or a pair that requires one of the two arrived with neither. |
automation_action_type_invalid | invalid_request_error | 422 | One of the steps declares an action type with no adapter behind it, so nothing would run at that position. |
automation_active_rules_limit_exceeded | payment_required_error | 402 | The company already has all the active automation rules its plan allows. |
automation_chain_depth_exceeded | invalid_request_error | 422 | One automation fired another until the chaining margin ran out, so the run stops before queueing any step. Waiting does not fix it: the same event would walk the same chain again. |
automation_condition_combinator_invalid | invalid_request_error | 422 | A branch of the condition declares a logical combinator outside the accepted set, so the branch cannot be read as an "and" or as an "or". |
automation_condition_depth_exceeded | invalid_request_error | 422 | The condition nests more levels than the evaluator walks, so the rule cannot be evaluated end to end. |
automation_condition_expression_invalid | invalid_request_error | 422 | The shape of the condition tree does not hold: a malformed node, an operator receiving the wrong kind of value, a field path that is not a dotted route, or a tree past the limit of depth or of nodes. |
automation_condition_field_not_evaluable | invalid_request_error | 422 | The condition reads a field the trigger does not publish as evaluable. The allowlist never resolves an unknown path to a default value, because a field resolved in silence is the very hole the sandbox exists to close. |
automation_condition_operator_invalid | invalid_request_error | 422 | A comparison of the condition names an operator outside the accepted set. |
automation_condition_operator_not_applicable | invalid_request_error | 422 | The operator does not apply to the type of the field it compares: asking whether one piece of text is greater than another is not a comparison the evaluator can make. |
automation_condition_operator_unsupported | invalid_request_error | 422 | The evaluator has no implementation for that operator, so it stops instead of answering "false": a silent "false" would make "the condition does not match" indistinguishable from "it cannot be evaluated". |
automation_condition_payload_field_missing | invalid_request_error | 422 | The key the condition reads is absent from the payload of the event, which is not the same as being present with a null value. Some events carry a reduced payload — a deletion, for instance, may only keep the identifier. |
automation_condition_payload_type_mismatch | invalid_request_error | 422 | The value in the event contradicts the type the trigger declares for that field, and the evaluator does not convert types: a converted comparison would give a right answer by accident and hide that the payload changed shape. |
automation_dry_run_event_type_mismatch | invalid_request_error | 422 | The dry run was asked with an event type other than the trigger of the rule being rehearsed, and a rule only ever receives events of its own trigger. The prediction would describe a delivery that is never going to happen. |
automation_event_company_unresolvable | invalid_request_error | 422 | The event reached the engine without a company that could be resolved, and the engine stops rather than guessing one: writing a run under a substituted company would break the isolation between companies. |
automation_event_payload_not_resolvable | invalid_request_error | 422 | The content of the event could not be recovered, so there is no payload to freeze into the run. It happens when the resource behind the event is no longer readable at the moment of delivery. |
automation_monthly_budget_exhausted | payment_required_error | 402 | The company used up the automation runs its plan includes for the current period, so the run stops before queueing any step. Unlike a rate limit, waiting a few seconds changes nothing: what ran out is the budget of the cycle. |
automation_portfolio_scope_forbids_action | invalid_request_error | 422 | One of the actions acts on the data of a single company, and under portfolio scope every run has a different tax ID of the portfolio as its subject. Only actions that notify the account owner, or that touch no entity at all, are admitted. |
automation_portfolio_scope_not_available | authorization_error | 403 | This company cannot create automations over a portfolio: either it has not been granted the accounting-practice module, or it is not the owner of its account. The portfolio is represented by the account owner, so an additional tax ID of the account never has a portfolio of its own. |
automation_rate_limit_exceeded | rate_limit_error | 429 | The company went over the automation runs its plan admits inside the limiter window. The work is admissible; it simply arrived too fast. |
automation_replay_not_allowed | invalid_request_error | 422 | The run exists and is yours, but relaunching it does not apply: it has not finished yet, it finished well and its effect already happened, its outcome would take exactly the same branch again, or no outcome was recorded for it. |
automation_rule_actions_empty | invalid_request_error | 422 | The rule declares no actions, so there would be nothing to run when its trigger fired. |
automation_rule_actions_limit_exceeded | invalid_request_error | 422 | The rule contains more than 50 actions. One triggering event would therefore fan out into too many steps, queued jobs, and possible external effects. |
automation_rule_already_deleted | invalid_request_error | 422 | The rule had already been taken down. Removal is logical and does not succeed in silence the second time, so two different removals never get confused with one another. |
automation_rule_company_mismatch | invalid_request_error | 422 | The rule that was about to be materialised does not belong to the company of the event, so the run is not created: freezing the snapshot of an event — client, amounts, tax id — onto rows of another company is never allowed. |
automation_rule_name_invalid | invalid_request_error | 422 | The name is empty or longer than the limit. The name is what identifies the rule in listings and in the history of its runs. |
automation_rule_not_found | not_found_error | 404 | No automation rule with that identifier exists for the authenticated company. A rule that belongs to another company answers exactly the same way, so the response never reveals whether it exists elsewhere. |
automation_rule_scope_immutable | invalid_request_error | 422 | The request tries to change the scope of an automation that already exists. Scope is fixed at creation because it decides whose events the rule observes, and changing it would reinterpret every run it has recorded so far. |
automation_rule_scope_invalid | invalid_request_error | 422 | The scope you sent is not in the automation catalogue. There are only two: the company that creates the rule, and the portfolio of its account (its other tax IDs and the ones another account cedes to it with operate level). |
automation_rule_status_transition_invalid | invalid_request_error | 422 | The rule cannot move from its current state to the one you asked for: activating, pausing and taking down each accept their own origin states. |
automation_rule_uuid_invalid | invalid_request_error | 422 | The identifier is not a valid UUID v7. Automations address their resources by the id the API returns, never by an internal number. |
automation_rule_version_not_found | not_found_error | 404 | The rule exists, but it has no version with that number: every save publishes a new version and the numbering never reuses a value. |
automation_rule_version_number_invalid | invalid_request_error | 422 | The version number is below 1. Versions are numbered from one upwards, in the order they were published. |
automation_rule_version_snapshot_not_found | not_found_error | 404 | The run points at a rule version whose frozen definition is not stored, so there is no definition to execute: a run always executes the version it started with, never the live rule. |
automation_run_not_found | not_found_error | 404 | No automation run with that identifier exists for the authenticated company. A run of another company answers exactly the same way, so the response never reveals whether it exists elsewhere. |
automation_run_status_transition_invalid | invalid_request_error | 422 | The run cannot move from its current state to the one requested: the life cycle of a run only admits the transitions its state declares. |
automation_run_step_not_found | not_found_error | 404 | The run exists and belongs to you, but it has no step at that index. A run materialises every one of its steps when it starts, and the count never changes afterwards. |
automation_run_uuid_invalid | invalid_request_error | 422 | The run identifier is not a valid UUID v7. |
automation_step_index_invalid | invalid_request_error | 422 | A step index cannot be negative: no run addresses a step that way. |
automation_step_status_transition_invalid | invalid_request_error | 422 | The step cannot move from its current state to the one requested. It is what stops a finished step from being claimed twice, and that guard is what makes a replay produce each effect only once. |
automation_step_subject_company_mismatch | invalid_request_error | 422 | The item the action was about to act on does not belong to the company of the run, or its company could not be determined. Either way the step aborts before the adapter is invoked, so no effect is produced. |
automation_subject_company_ownership_not_verified | invalid_request_error | 422 | While preparing the run it could not be proven that the company behind the event is still in the portfolio of the account of whoever created the automation, reachable with operate level and active. The tax ID may have been archived, deactivated or transferred to another account, the relation that ceded it may have been revoked, ended or lowered to read-only, or the run reached this point with mismatched data. |
automation_trigger_not_found | not_found_error | 404 | The trigger is not in the catalogue your company can see. A name that does not exist and a real trigger whose module your company has not been granted answer the same, so the response never confirms which of the two it is. |
automation_trigger_payload_contract_unknown | invalid_request_error | 422 | The trigger publishes no contract of evaluable fields, so there is no catalogue against which to resolve a condition. |
automation_trigger_type_invalid | invalid_request_error | 422 | The write carries a trigger that is not in the catalogue available to your company, so the rule would never receive an event. |
Billing
| Code | Type | HTTP | Description |
|---|---|---|---|
customer_offer_benefit_invalid | invalid_request_error | 422 | The offer conditions are invalid. Review the indicated fields. |
customer_offer_billing_state_conflict | conflict_error | 409 | The billing state has changed or needs review. Check the operation before continuing. |
customer_offer_catalog_unavailable | service_unavailable_error | 503 | The billing catalog is not configured or cannot be verified; this is not a restriction on the customer plan. |
customer_offer_collection_not_restorable | invalid_request_error | 422 | The purchase cannot be collected or its balance safely restored. No debt is left for another invoice. |
customer_offer_combination_invalid | invalid_request_error | 422 | Extra trial days can only combine with a permanent plan discount or price. |
customer_offer_discount_conflict | conflict_error | 409 | An offer or discount already applies to the same product. Benefits do not stack automatically. |
customer_offer_forbidden | authorization_error | 403 | The operation does not satisfy the current conditions or permissions. |
customer_offer_gateway_unavailable | service_unavailable_error | 503 | The payment provider is unavailable. Check this operation before retrying. |
customer_offer_idempotency_conflict | idempotency_error | 409 | This attempt already belongs to different conditions. Keep the operation and check its status. |
customer_offer_invalid_terms | invalid_request_error | 422 | The offer conditions are invalid. Review the indicated fields. |
customer_offer_legacy_outcome_unknown | conflict_error | 409 | A previous billing operation is still awaiting verification. |
customer_offer_negotiated_price_invalid | invalid_request_error | 422 | Review the agreed net price, product, interval and number of billing cycles. |
customer_offer_not_eligible | invalid_request_error | 422 | This offer is incompatible with the company, product or current status. |
customer_offer_operation_in_progress | conflict_error | 409 | An operation is already in progress for this product. Check its status before continuing. |
customer_offer_payment_method_required | payment_required_error | 402 | This purchase needs a payment method. Add one and refresh the terms before confirming. |
customer_offer_phase_incompatible | conflict_error | 409 | The subscription has an incompatible scheduled change. It has not been overwritten. |
customer_offer_price_mapping_conflict | conflict_error | 409 | The billing state has changed or needs review. Check the operation before continuing. |
customer_offer_purchase_failed | payment_required_error | 402 | Payment failed and this purchase was verified as not applied. Check the operation before trying again. |
customer_offer_quote_changed | conflict_error | 409 | The conditions have changed. Refresh the quote before confirming. |
customer_offer_quote_expired | conflict_error | 409 | The quote has expired. Refresh it and review the conditions. |
customer_offer_quote_unavailable | service_unavailable_error | 503 | The amount cannot be verified. Confirmation is blocked. |
customer_offer_state_conflict | conflict_error | 409 | The billing state has changed or needs review. Check the operation before continuing. |
customer_offer_trial_baseline_changed | conflict_error | 409 | The trial has changed. Refresh the quote to see the current end date. |
customer_offer_trial_limit_exceeded | invalid_request_error | 422 | This extension would exceed the maximum 180 trial days. |
customer_offer_trial_not_eligible | invalid_request_error | 422 | You can only extend an active trial of the agreed plan. An expired trial cannot restart. |
customer_offer_unavailable | invalid_request_error | 422 | This offer is unavailable, expired or has no redemptions left. |
Companies
| Code | Type | HTTP | Description |
|---|---|---|---|
additional_nif_charge_failed | payment_required_error | 402 | The immediate charge for the additional tax ID was declined: the card was refused, it needs authentication, or the payment provider was unreachable. When the charge fails, the tax ID is not added or activated and no charge remains. |
additional_nif_not_in_plan | authorization_error | 403 | The account holds a live plan, but that plan does not include additional tax IDs: only Empresario and Enterprise (trials included) allow them. Nothing was charged and no change was written. |
additional_nif_plan_required | payment_required_error | 402 | The account has no live plan, so there is no subscription on which to charge the additional tax ID. Nothing was charged and no change was written. |
billing_managed_by_provider | authorization_error | 403 | This account's billing is paid by another account, so it cannot contract an additional tax ID on its own. Nothing was charged and no change was written. |
company_inactive | authorization_error | 403 | The company named by the {company} path segment is within the credential's scope, but it is deactivated and cannot be operated until it comes back. |
payment_method_required | payment_required_error | 402 | Adding or activating an additional tax ID charges its fee immediately, and the account operates in live mode with no payment method on file. Nothing was charged and no change was written. |
Contacts
| Code | Type | HTTP | Description |
|---|---|---|---|
alternative_id_type_invalid | invalid_request_error | 422 | The alternative identifier type is outside the catalogue nif_iva, passport, country_id, residence_certificate, other_document, not_registered. |
bank_account_usage_required | invalid_request_error | 422 | The bank account does not declare what it is for: neither collection nor payment, and it does not flag a default usage to infer it from. An account with no purpose cannot be used for collections or payments. |
cannot_have_both_tax_id_and_alternative_id | invalid_request_error | 422 | The client sends tax_id and an alternative identifier at the same time. Fiscal identity is one: the alternative identifier exists precisely for parties without a Spanish tax id. |
census_requires_tax_id | invalid_request_error | 422 | Census verification checks the pair name plus tax id against AEAT, and one of the two is missing. |
client_has_documents | invalid_request_error | 422 | The client is referenced by issued documents. Deleting it would leave invoices, quotes or delivery notes without the party they were issued to, and fiscal records must remain traceable. |
client_import_too_large | invalid_request_error | 422 | The CSV exceeds the row limit the synchronous import accepts, since the whole file is processed within the request. |
client_not_found | not_found_error | 404 | The identifier does not resolve to any client of the authenticated company. |
client_requires_tax_identity | invalid_request_error | 422 | The client carries no fiscal identity: neither tax_id nor an alternative identifier, and an invoice cannot be issued to an unidentified party. |
contact_not_found | not_found_error | 404 | The identifier does not resolve to any business contact of the authenticated company. |
direct_debit_requires_default_bank_account | invalid_request_error | 422 | Direct debit was selected as the payment method, but the client has no default bank account to charge. |
import_not_found | invalid_request_error | 404 | The contact import or its report is unavailable in the authenticated company. |
mapping_header_not_found | invalid_request_error | 422 | A column in the import mapping does not exist in the uploaded file headers. |
supplier_has_documents | invalid_request_error | 422 | The supplier is referenced by registered expenses, and deleting it would leave those expenses without the party that issued them. |
supplier_not_found | not_found_error | 404 | The identifier does not resolve to any supplier of the authenticated company. |
tax_id_already_exists | conflict_error | 409 | Another client of the company already holds that tax id, and the tax id identifies the party uniquely inside a company. |
Delivery Notes
| Code | Type | HTTP | Description |
|---|---|---|---|
delivery_note_cannot_be_sent | invalid_request_error | 422 | The delivery note is already invoiced or cancelled: delivering it now would hand the customer a superseded document. |
delivery_note_not_found | not_found_error | 404 | The identifier does not resolve to any delivery note of the authenticated company. |
delivery_note_section_not_editable_in_status | invalid_request_error | 422 | The logistics section — carrier, vehicle, driver — is frozen because the delivery note is already delivered, invoiced or cancelled. |
driver_tax_id_requires_name | invalid_request_error | 422 | The driver tax id was sent without the driver name, and an identifier with no name identifies nobody on the delivery document. |
signature_payload_too_large | invalid_request_error | 422 | The signature image exceeds the accepted size for the field. |
Employees
| Code | Type | HTTP | Description |
|---|---|---|---|
employee_batch_billing_state_conflict | conflict_error | 409 | Billing needs review before this operation can continue. |
employee_batch_forbidden | authorization_error | 403 | You no longer have permission for this operation. Check its status before starting another. |
employee_batch_idempotency_conflict | idempotency_error | 409 | This request belongs to different details. Review the operation before preparing a new batch. |
employee_batch_quote_changed | conflict_error | 409 | The conditions changed. Refresh the quote and accept the new amount. |
employee_batch_quote_expired | conflict_error | 409 | This quote expired. Refresh it and review the amount. |
employee_batch_quote_unavailable | service_unavailable_error | 503 | A reliable amount is unavailable. Retry without starting another payment. |
employee_batch_state_conflict | conflict_error | 409 | This action is no longer available. Check the current operation status. |
employee_inactive | invalid_request_error | 422 | The employee has been terminated: they are read-only and accept no new operations, such as clocking in, being assigned a schedule or an absence policy, having an absence that runs past their termination date approved, or being invited to the portal. Nothing was written. |
employee_not_found | not_found_error | 404 | The employee does not exist or is not accessible in this company. |
employee_seat_charge_failed | payment_required_error | 402 | The immediate pro-rated charge for the employee seat was declined: the card was refused, it needs authentication, or the payment provider was unreachable. The employee is not activated if the seat is not paid. |
employee_seat_mutation_outcome_unknown | conflict_error | 409 | A previous employee operation is still awaiting verification. Do not repeat the charge. |
employee_seat_operation_in_progress | conflict_error | 409 | A seat operation is in progress. Recover it before starting another. |
employee_seat_payment_method_required | payment_required_error | 402 | Adding or reactivating an employee charges a seat immediately, and the company operates in live mode with no payment method on file. |
employee_seat_phase_incompatible | conflict_error | 409 | The subscription has scheduled terms that this seat mutation cannot preserve. |
employee_seats_not_in_plan | authorization_error | 403 | The account's plan does not include time tracking (the control_horario module, by plan or by a manual grant), so employee seats cannot be bought. Nothing was charged and no change was written; lowering or keeping the contracted seats stays allowed. |
invalid_hire_date | invalid_request_error | 422 | The employee's hire date would fall after their termination date: either hire_date was changed to a date later than the recorded termination, or the employee was deactivated with a termination_date earlier than the hire date. The employee is left unchanged. |
Events
| Code | Type | HTTP | Description |
|---|---|---|---|
event_not_found | not_found_error | 404 | The identifier does not match any event of the authenticated company, or the event was purged by the 30-day retention policy. |
Exports
| Code | Type | HTTP | Description |
|---|---|---|---|
export_budget_exceeded | rate_limit_error | 429 | The hourly budget of PACKAGING WORK for the company is exhausted. This is not a request limit: it counts packaged documents and generated artifacts against the disk and render pool shared by every tenant, so neither spreading the calls nor using another credential changes anything. The subcode says which of the two axes ran out — export_documents_budget (packaged content) or export_artifacts_budget (number of generated files). |
export_byte_cap_exceeded | invalid_request_error | 413 | The packaged download exceeds the BYTE cap of that artifact type. It counts weight, not documents, so a small batch of very heavy documents —illustrated template, attachments— reaches it too. The subcode says when it was rejected: before_writing, when the estimated weight already exceeded it and NOTHING was written, or while_writing, when the real weight exceeded it mid-packaging and the partial file was discarded. |
export_document_cap_exceeded | invalid_request_error | 413 | The packaged download asks for MORE DOCUMENTS than that artifact type allows. It is not a request limit nor a permissions problem: it is the size of what a single call asks for, and the very same cap rules the web application and the API, so splitting the work across surfaces does not dodge it. |
Managed companies
| Code | Type | HTTP | Description |
|---|---|---|---|
gestoria_seat_preview_unavailable | service_unavailable_error | 503 | The managed-company seat charge could not be verified; this does not mean the purchase is contractually free. |
Idempotency
| Code | Type | HTTP | Description |
|---|---|---|---|
idempotency_key_in_use | idempotency_error | 409 | Another request with the same Idempotency-Key is still in flight, and the result is not known yet. |
idempotency_key_invalid | invalid_request_error | 400 | The Idempotency-Key does not fit the accepted format: it must be 1 to 255 printable ASCII characters. |
idempotency_key_required | invalid_request_error | 422 | The request arrived without an Idempotency-Key header, and this operation delivers an effect that cannot be taken back — an email sent, a file generated, a charge — so its transition window has already closed for this credential's environment. |
idempotency_key_reused | idempotency_error | 422 | That Idempotency-Key was already used with a different payload. The key identifies one specific operation, so reusing it for another would make replay meaningless. An external_id already issued that is resent with a different type or total in POST /v1/companies/{company}/invoices does not return this error but the 409 unattended_replay_mismatch. |
Integration
| Code | Type | HTTP | Description |
|---|---|---|---|
charge_rule_invalid | invalid_request_error | 422 | The rule is inconsistent: the condition, the outcome, the not-invoiced reason, the concept or the VAT rate do not fit together or are not valid. The conflicting field is reported in param. |
charge_rule_limit_reached | invalid_request_error | 422 | The Stripe account already has the maximum number of charge treatment rules. |
charge_rule_not_found | not_found_error | 404 | The charge treatment rule does not exist on the given Stripe account or does not belong to your company. |
connect_return_domain_already_exists | conflict_error | 409 | The host you are trying to add is already one of the return domains of your account. It is compared normalized (lower case, no port or path), so App.Example.com and app.example.com are the same domain. |
connect_return_domain_limit_reached | invalid_request_error | 422 | Your account already has the maximum number of return domains it allows, and the new one was not saved. The cap is per account and counts every registered domain. |
connect_return_domain_not_found | not_found_error | 404 | The return domain named in the path does not exist in your account, or belongs to another one: both answers are identical on purpose so the domains of other accounts are never revealed. |
connect_return_url_not_allowed | invalid_request_error | 422 | The host of the return_url is not among the return domains of the account of the key you use to start the Stripe connection. Only https addresses whose exact host (no wildcards) is registered on that account are accepted, so nobody can send the person to a site you do not control. |
invalid_connection_method | invalid_request_error | 422 | The connection method does not exist for this provider. |
platform_account_subscriptions_owned_by_billing | invalid_request_error | 422 | The connected Stripe account is the platform's own account: Factuarea's subscription fees are invoiced by Billing directly, so that account does not support subscription autoinvoicing (subscription_autoinvoicing_enabled). |
shopify_api_version_expired | api_error | 500 | The Admin API version this connector speaks to the shop with is no longer supported. Shopify does not return an error when that happens: it serves the oldest stable version with a 200, so the breakage shows up as fields quietly missing from the response. |
shopify_credentials_rejected | invalid_request_error | 422 | The shop answered and rejected the access token, or there was none to use. In Shopify the token comes from authorising the app, and the merchant can revoke that authorisation from their admin at any time, so a token that worked yesterday may not work today without anyone changing a setting. |
shopify_store_unreachable | api_error | 502 | The shop did not answer: the request timed out, the transport failed, Shopify returned an error of its own, or the Admin API query cost budget was exhausted. What is failing sits upstream, not in the credential. |
store_already_connected | invalid_request_error | 422 | That shop is already connected to your company under the same provider. The pair provider plus remote shop is unique per company, so connecting it twice would leave two stores ingesting the same orders and invoicing them twice. |
store_external_id_mismatch | invalid_request_error | 422 | The remote identifier you are sending does not match any shop your company has authorised for that integration. With providers that sign their notifications using the application secret — Shopify — that identifier decides which company each sale is invoiced to, so only a shop that went through the authorisation flow is accepted. |
store_not_found | not_found_error | 404 | The identifier does not resolve to any connected store of the authenticated company. A store belonging to another company answers exactly the same way, so the response never reveals whether it exists elsewhere. |
store_url_not_allowed | invalid_request_error | 422 | The base address of the shop is not an authorised outbound destination for your company. Reading orders back from the shop would open a connection to a host nobody approved. |
stripe_account_linked_elsewhere | conflict_error | 409 | That Stripe account is already linked and active in another Factuarea company. An active Stripe account can only belong to one company. |
stripe_oauth_exchange_failed | invalid_request_error | 422 | Stripe did not confirm the account authorization: the authorization code expired, was already used or was denied. |
woocommerce_credentials_rejected | invalid_request_error | 422 | The shop answered and rejected the credential, or the credential could not be used at all: the key is missing, the secret is missing, or the base address is not https. Authentication travels in the header over HTTPS, so a shop published in clear text would hand over both pieces on the first hop, which is why it is rejected before anything leaves. |
woocommerce_rest_route_missing | invalid_request_error | 422 | The shop answered, but its REST API is not published: WordPress replied that the route does not exist. The usual cause is permalinks left on the plain setting, so /wp-json/ is not served. The credential may be perfectly valid. |
woocommerce_store_unreachable | api_error | 502 | The shop did not answer: the request timed out, the transport failed, or its hosting returned an error of its own. What is failing sits upstream, in the merchant's installation, not in the platform and not in the credential. |
Invoices
| Code | Type | HTTP | Description |
|---|---|---|---|
amount_reconciliation_failed | invalid_request_error | 422 | The amounts with VAT included cannot be split into line amounts that add up to exactly the amount charged, so nothing was issued rather than alter the total. A withholding or an equivalence surcharge that moves the total by more than a rounding difference causes it. |
corrective_client_change_requires_substitution | invalid_request_error | 422 | The corrective is issued to a client other than the original invoice's (for instance, after an error in the client data): it can only be a substitution, because by differences the amount would be attributed to someone who never received the invoice. |
corrective_full_cancellation_with_lines | invalid_request_error | 422 | Voiding the whole invoice by differences (correction_type: full with correction_nature: I) takes no lines: the corrective copies every original line back negated. |
corrective_invoice_inanulable | invalid_request_error | 422 | The invoice is itself a corrective, and correctives are never annulled: the correction chain has to stay auditable end to end. |
corrective_substitution_negative_amount | invalid_request_error | 422 | In a substitution corrective (correction_nature: S, or full with lines and no nature) each line carries the FINAL amount of the correct invoice, so no quantity can be negative (art. 15.5 RD 1619/2012; VERI*FACTU does not accept a negative base in a substitution). The unit price is never negative: the sign goes in the quantity. |
corrective_substitution_requires_full | invalid_request_error | 422 | A substitution corrective (correction_nature: S) replaces the whole invoice; there is no partial substitution. |
exemption_cause_contradicts_taxed_lines | invalid_request_error | 422 | The invoice carries a header exemption cause that declares the operation VAT-free (exemption, non-subject or reverse charge) and an operation line has a VAT rate above zero. |
export_limit_exceeded | invalid_request_error | 422 | The filtered selection exceeds the 5,000-invoice cap of the export, so the file is refused up front instead of being silently truncated. |
face_submission_attempt_conflict | conflict_error | 409 | Another request changed the FACe submission attempt (claim or reconciliation) while you were acting on it. |
face_submission_completion_failed | api_error | 500 | FACe answered the submission but the platform could not store the result locally. |
face_submission_rejected | invalid_request_error | 422 | FACe analysed the submission and rejected it with its own error code (for example a wrong DIR3 code, an invalid signature or a duplicate). Unlike an uncertain transmission, FACe did not register the invoice. |
face_transmission_uncertain | conflict_error | 409 | The invoice was sent to FACe but its outcome is unknown, so FACe may or may not have registered it. |
facturae_artifact_unavailable | api_error | 500 | The Facturae file retained for that submission cannot be read from storage because it is missing or damaged. The failure is on our side. |
facturae_operation_forbidden | authorization_error | 403 | The actor cannot perform that Facturae operation; details.reason tells whether it is a matter of the actor's permissions, the issuer's authority, access to the invoice or the right to send it. |
invalid_correction_nature | invalid_request_error | 422 | correction_nature only accepts I (by differences: the corrective carries the amount of the rectification, with its sign) or S (substitution: it carries the invoice as it ends up, with the final lines). |
invalid_correction_reason | invalid_request_error | 422 | The correction reason is outside the closed fiscal list (error_fundado, concurso, incobrable, error_importe, error_cliente, devolucion, descuento, otras), which maps to the AEAT codes R1 to R4. |
invalid_delivery_channel | invalid_request_error | 422 | The delivery channel is outside the catalogue, which has only two values: email (recorded automatically when the mail server accepts the message) and manual (a delivery you made by your own means). |
invalid_facturae_structured_data | invalid_request_error | 422 | The structured data needed to build the Facturae file is not valid: a value is wrong, the totals do not match the lines, or the generated XML fails the schema. |
invalid_invoice_business_data | invalid_request_error | 422 | The business data of the invoice (line references, administrative centres or their roles) contains an invalid value. |
invalid_invoice_id | invalid_request_error | 400 | The invoice reference received is not a valid identifier; it usually means an internal value slipped in where the API expects the public id. |
invalid_invoice_number | invalid_request_error | 422 | The invoice number does not follow the numbering format of its series (by default SERIES-YYYY-NNN; correctives carry the correlative number of their own series, e.g. R-2026-001). |
invalid_invoice_payment_terms | invalid_request_error | 422 | The payment schedule of the invoice breaks a rule, for example installments that do not add up to the total, invalid dates or a missing contractual bank account. |
invalid_invoice_status | invalid_request_error | 422 | The value sent as invoice status is outside the document lifecycle catalogue (draft, scheduled, issued, overdue, cancelled, annulled). Before API version 2026-10-01 issued is published as sent, and wherever the API reads a status as input (the status filters, the bulk status change) sent is taken as issued. paid is a valid value to read and to filter by, but not to write: register a payment instead. |
invalid_invoice_uuid | invalid_request_error | 400 | The invoice identifier in the path or in the payload is not a valid UUID. |
invalid_payment_method | invalid_request_error | 422 | The payment method is outside the closed allowlist: bank_transfer, cash, credit_card, sepa_direct_debit, paypal, bizum, other. |
invoice_administrative_precondition_required | invalid_request_error | 428 | The change to the administrative routing did not state which version it is based on. |
invoice_administrative_version_conflict | conflict_error | 409 | The administrative routing of the invoice (its administrative centres) changed after you read it. |
invoice_already_annulled | invalid_request_error | 422 | The invoice was already annulled. Annulment is terminal and, with VeriFactu active, its annulment record has already reached AEAT. |
invoice_already_paid | invalid_request_error | 422 | The invoice is already settled. paid is a terminal, accounting-closed state: the output VAT has been declared, or will be declared for the period. |
invoice_already_rectified_in_full | invalid_request_error | 422 | The invoice is already voided in full (a full corrective by differences), so it admits no further corrective; or it is replaced in full, so it admits no second full correction. |
invoice_already_sent | invalid_request_error | 422 | The invoice was already issued: it holds a definitive series number and, with VeriFactu active, its registration with AEAT. Issuing does not happen twice. |
invoice_cannot_assign_number | invalid_request_error | 422 | A definitive number was requested for an invoice that is not a draft, or that already carries one. Series numbering is monotonic and numbers are never reassigned. |
invoice_cannot_be_marked_as_sent | invalid_request_error | 422 | The delivery mark records that an issued invoice reached the customer, so it only applies to issued or overdue invoices. A draft or a scheduled invoice is not the fiscal invoice yet, and a cancelled or annulled one no longer is. |
invoice_cannot_be_sent | invalid_request_error | 422 | The invoice is voided or cancelled: it no longer represents a valid operation, so its PDF is not delivered to the recipient. |
invoice_due_date_not_last_instalment | invalid_request_error | 422 | The invoice has a payment schedule and its due date (due_on) is missing or is not the date of the last installment, which is when the invoice falls due. |
invoice_invalid_status_transition | invalid_request_error | 422 | The target status is unreachable from the current one. The document lifecycle is directed: draft moves to scheduled, issued or cancelled, scheduled back to draft or on to issued, issued to overdue or annulled, overdue to annulled, and cancelled and annulled are terminal. The lifecycle is the same in every API version; before 2026-10-01 the issued status is published as sent. Being paid is not a step of that lifecycle: it is read from the payment ledger. |
invoice_not_cancellable_in_current_state | invalid_request_error | 422 | Cancelling withdraws a draft that is not yet fiscally binding, so it only applies while the invoice is draft. |
invoice_not_correctable_in_current_state | invalid_request_error | 422 | A corrective invoice can only be issued against an invoice that is already issued, paid or not: issued or overdue (an issued invoice is published as sent before API version 2026-10-01). A draft, a scheduled, a cancelled or an annulled invoice has nothing to correct. |
invoice_not_deletable_in_current_state | invalid_request_error | 422 | Only draft and cancelled invoices can be deleted. A numbered invoice never disappears: the correlative sequence must stay auditable. |
invoice_not_editable_in_current_state | invalid_request_error | 422 | Only a draft admits editing. Once issued, the invoice is immutable and its content is frozen along with its fiscal record. |
invoice_not_eligible_for_action | invalid_request_error | 422 | The requested action does not apply to this invoice: its type or its current state leaves it outside the scope of the operation. |
invoice_not_found | not_found_error | 404 | The identifier does not resolve to any invoice of the authenticated company. Invoices belonging to another company answer exactly the same way. |
invoice_not_modifiable_in_current_state | invalid_request_error | 422 | The field you are changing is frozen for the current state — for instance the tax regime of an annulled invoice. |
invoice_not_paid | invalid_request_error | 422 | A payment receipt was requested for an invoice with no settled payment, so there is nothing to certify. |
invoice_not_reschedulable_in_current_state | invalid_request_error | 422 | Rescheduling moves the issuing date of an invoice that is waiting in scheduled, and this invoice is not waiting. |
invoice_not_schedulable_in_current_state | invalid_request_error | 422 | Only a draft can be scheduled: scheduling reserves a future issuing moment without consuming a series number yet. |
invoice_not_unschedulable_in_current_state | invalid_request_error | 422 | Unscheduling returns an invoice from scheduled to draft, so it only applies while it is still waiting to be issued. |
invoice_not_unsendable_in_current_state | invalid_request_error | 422 | Undoing the delivery mark only applies to an issued invoice (issued or overdue; published as sent before API version 2026-10-01) with no active payments: it clears sent_at and sent_via and keeps its fiscal status. |
invoice_payment_terms_precondition_required | invalid_request_error | 428 | The change to the payment schedule did not state which version it is based on. |
invoice_payment_terms_version_conflict | conflict_error | 409 | The payment schedule of the invoice changed after you read it. |
invoice_requires_at_least_one_line | invalid_request_error | 422 | The invoice carries no operation line, so it has no taxable base and cannot be issued. This happens both when you send no lines at all and when every line you send is a disbursement: a disbursement is an amount paid on the customer's behalf (art. 78.Tres.3 LIVA), not an operation of your own. |
invoice_type_change_not_allowed | invalid_request_error | 422 | Only a draft can switch between a complete invoice (F1) and a simplified one (F2). A corrective invoice, a substitute invoice (F3) or a corrective invoice of a simplified one (R5) keep their type, and a simplified invoice without a client cannot become a complete one until you set the recipient. |
invoice_without_retained_presentation | invalid_request_error | 422 | An invoice of the quarter has no retained document presentation (it predates capture or was never initialized), so it cannot be included in the quarterly package. It appears as error_code in the failures of the quarterly ZIP manifest, where the invoice is left out, and as the subcode of a business rule violation in the quarterly email. |
invoice_year_required_for_ambiguous_number | invalid_request_error | 422 | That invoice number matches more than one invoice, so on its own it identifies none. It repeats for two independent reasons: the fiscal year (series recycle numbering every year) and the series (two series of your company each issue their own F-2026-001). |
line_total_checksum_mismatch | invalid_request_error | 422 | The line_total you declared does not match the one Factuarea computes for that line (quantity × price − discount + VAT − withholding + surcharge) and the deviation is above the one-cent tolerance. The amount that gets invoiced and reported to the tax authority is always the one computed here, so the discrepancy means your system and the issued invoice would not reconcile. |
line_type_invalid | invalid_request_error | 422 | The line type falls outside the closed NORMAL / SUPLIDO catalogue. An issued invoice only tells two natures apart: what you sell, which forms the taxable base and carries VAT, and a disbursement (suplido), money advanced in the name and on behalf of the customer, which is therefore left out of the base (art. 78.Tres.3 of the Spanish VAT Act). |
no_invoices_in_period | invalid_request_error | 422 | The quarterly operation found no invoices in the requested period, so there is nothing to package or send. |
operation_date_after_issue_date | invalid_request_error | 422 | operation_on is later than issued_on. An operation date after the issue date is only valid for advance payments (regime key 14 or 15). |
pack_return_invalid | invalid_request_error | 422 | The return of a pack component in a corrective invoice breaks the rules of returns. The pack is not in the invoice being corrected, the product is not one of its components, the quantity is not negative, the price differs from the original split price or more units are returned than were sold. |
payment_method_invalid | invalid_request_error | 422 | Same closed allowlist as invalid_payment_method, reported when the value is rejected while reading the payment method field of the payload. |
rectified_invoice_inanulable | invalid_request_error | 422 | This invoice already has a full corrective (correction_type: full), which returned its amount and its goods. Annulling it now would return both a second time. A partial corrective does not block: the invoice stays alive and annulling it is legitimate. |
reminder_not_applicable | invalid_request_error | 422 | The payment reminder does not apply: the invoice is not issued or overdue (an issued invoice is published as sent before API version 2026-10-01), there is no recipient email, the public link is missing or disabled, or another reminder went out in the last 24 hours. |
scheduled_for_in_past | invalid_request_error | 422 | scheduled_for is not strictly in the future, so there is no waiting period to reserve. |
simplified_invoice_cannot_be_substituted | invalid_request_error | 422 | One invoice of the substitution list cannot be replaced: it is not simplified, it is cancelled or annulled, it belongs to another company, or it already has a substitute. |
simplified_invoice_not_allowed | invalid_request_error | 422 | The operation is not eligible for a simplified invoice: it exceeds EUR 3,000, or it is an intra-EU supply, an export, a reverse-charge operation, or the customer needs a full invoice to deduct VAT. |
simplified_invoices_disabled | invalid_request_error | 422 | The company has not enabled simplified invoices, so an invoice of type F2 cannot be created. |
simplified_limit_exceeded | invalid_request_error | 422 | The lines would push the simplified invoice (F2) over the absolute legal cap of EUR 3,000 VAT included. |
suplido_line_cannot_carry_taxes | invalid_request_error | 422 | The disbursement line carries charges of its own: a VAT rate, withholding, equivalence surcharge, discount, regime key, exemption cause or product/pack. A disbursement is not an operation of the issuer, so charging tax on it would mean paying tax on a supply you never made, and tying it to a product would move stock you never sold. |
suplido_not_allowed_in_simplified_invoice | invalid_request_error | 422 | The invoice is simplified (F2) and a simplified invoice does not identify the recipient. With no identified recipient there is nobody to evidence the payment on behalf of, so the amount cannot take disbursement treatment on this invoice type. |
suplido_requires_source_invoice_reference | invalid_request_error | 422 | The disbursement line does not carry source_invoice_reference, the number of the supporting document the third party issued in the customer's name. Without that document the payment is not evidenced as made on someone else's behalf, and the tax authority would treat it as the issuer's own taxable base, with VAT charged on it. |
tax_rate_mismatch | invalid_request_error | 422 | The line chooses a tax by id (tax_rate_id, retention_rate_id or surcharge_rate_id) and contradicts it: it declares a tax_rate, retention_rate or surcharge_rate different from that tax's rate, or the tax is of another class than its field (for example a withholding tax in surcharge_rate_id). The chosen VAT tax also qualifies the line (regime, AEAT qualification and exemption reason), so both values must match. |
unattended_replay_mismatch | idempotency_error | 409 | An invoice with that external_id was already issued with a different type or total, so the request cannot be treated as a resend of the same sale. It is answered with 409, code and subcode unattended_replay_mismatch and param=external_id: the external_id identifies ONE operation and does not expire. It is not idempotency_key_reused, the 422 of an Idempotency-Key reused with a different payload. |
MCP
| Code | Type | HTTP | Description |
|---|---|---|---|
mcp_guardrail_violation | invalid_request_error | 422 | The call breaks a declared tax rule and was rejected LOCALLY, before anything ran: no document was created, modified or deleted. It is the only code in the catalogue that no API v1 route can emit — whoever receives it is talking over MCP. The subcode says which of the nine guardrails was broken, and the error data carries guardrail_uri (the resource that explains the rule) and rule_id (the specific rule, shaped BR-XXX-NNN). |
Notifications
| Code | Type | HTTP | Description |
|---|---|---|---|
notification_not_found | not_found_error | 404 | The identifier does not match any notification of the authenticated company, or the notification fell out of the retention window. |
Payments
| Code | Type | HTTP | Description |
|---|---|---|---|
invalid_payment_date | invalid_request_error | 422 | The payment date cannot be later than today. A date before the issue date is accepted and recorded as an advance payment. |
payment_already_reversed | invalid_request_error | 422 | The payment is already reverted, and its trail is not overwritten by a second reversal: the reason, instant and author of the first one are the accounting record of why the invoice stopped being paid. |
payment_reversal_invalid | invalid_request_error | 422 | The reversal note is longer than the 500 characters allowed. |
payment_reversal_reason_invalid | invalid_request_error | 422 | The reversal reason is outside the closed catalog: only a returned SEPA direct debit, a card dispute or chargeback, a misapplied payment, a dishonoured bill and a recording error are accepted. |
payout_reconciliation_amount_mismatch | invalid_request_error | 422 | The confirmed amount does not match the net amount of the payout, so the reconciliation would close with a difference nobody accounts for. |
receipt_not_available | invalid_request_error | 422 | There is no receipt to issue because the document has no settled payment behind it. |
reversal_reason_reserved | invalid_request_error | 422 | The reason issued_in_error is reserved for annulling an invoice that was issued by mistake; it cannot be used to revert a single payment. |
stripe_payout_already_reconciled | invalid_request_error | 422 | The payout was already reconciled, and reconciliation is terminal: repeating it would double-count the bank entry. |
stripe_payout_not_found | not_found_error | 404 | The identifier does not resolve to any payout of the authenticated company. |
| Code | Type | HTTP | Description |
|---|---|---|---|
invalid_pdf_artifact_fingerprint | invalid_request_error | 422 | The PDF artifact fingerprint is invalid. |
invalid_pdf_template_configuration | invalid_request_error | 422 | A value of the template configuration breaks a rule of the template model; param gives the path of the offending field. |
pdf_artifact_not_found | not_found_error | 404 | The PDF artifact does not exist for this company, or it was a preview that has expired. |
pdf_artifact_not_ready | service_unavailable_error | 503 | The PDF is still being prepared. |
pdf_commercial_identity_not_found | not_found_error | 404 | The commercial identity does not exist in this company. |
pdf_commercial_identity_required | invalid_request_error | 422 | The brand mode of the template (logo or image) needs a commercial identity and the company has no default one to fall back on. |
pdf_commercial_identity_unavailable | invalid_request_error | 422 | The commercial identity exists but is archived or incompatible with this operation. |
pdf_engine_profile_unavailable | api_error | 500 | The PDF rendering profile is unavailable. |
pdf_engine_unreachable | service_unavailable_error | 503 | The PDF engine did not answer (down, restarting or in the middle of a deployment). It is transient: the same request works when the engine is back, and nothing was created or changed. |
pdf_image_resource_unavailable | api_error | 500 | The PDF image resource is unavailable. |
pdf_legal_source_changed | conflict_error | 409 | The current legal source no longer matches this retained presentation. |
pdf_library_association_coverage_incomplete | api_error | 500 | The platform could not verify every default, series or recurrence that uses the template, so the impact of the operation cannot be guaranteed. The failure is on our side. |
pdf_library_impact_conflict | conflict_error | 409 | The defaults, series or recurrences affected by the operation changed after you reviewed its impact. |
pdf_main_template_required | conflict_error | 409 | The company already works with the PDF template library, where the design (pdf_template) and accent colour (accent_color) of the personalization are applied to its main template, and it has no main template to apply them to. |
pdf_original_corrupt | api_error | 500 | The integrity of the original PDF cannot be verified. |
pdf_original_layout_unavailable | api_error | 500 | The layout the original PDF was generated with is no longer available in this version of Factuarea. |
pdf_original_unavailable | api_error | 500 | The original PDF is unavailable. |
pdf_payload_resource_unavailable | api_error | 500 | The resources required to prepare the PDF are unavailable. |
pdf_presentation_conflict | conflict_error | 409 | The presentation changed after you read it, so the expected_version you sent is stale. |
pdf_presentation_context_changed | conflict_error | 409 | The data the preview was built from (document, company or template context) changed after the preview was produced. |
pdf_presentation_etag_mismatch | conflict_error | 412 | The ETag sent in If-Match no longer matches the stored presentation, which was modified after you read it. |
pdf_presentation_invalid | invalid_request_error | 422 | The presentation does not satisfy a field or content rule. |
pdf_presentation_not_found | not_found_error | 404 | The document presentation does not exist for this company or does not belong to the document you queried. |
pdf_presentation_not_ready | invalid_request_error | 422 | The revisioned presentation is not available for this company yet: its activation is pending. |
pdf_presentation_precondition_required | invalid_request_error | 428 | The change to the presentation did not state which version it is based on. |
pdf_signature_personal_data_forgotten | not_found_error | 410 | Personal signature data for this presentation has been erased. |
pdf_template_access_denied | authorization_error | 403 | The credential or user does not have permission to perform this operation on the PDF template library. |
pdf_template_archived | invalid_request_error | 422 | The PDF template is archived, and an archived template cannot be assigned or edited. |
pdf_template_asset_conflict | conflict_error | 409 | A template asset with that identifier already exists, so the upload would overwrite it. |
pdf_template_asset_not_found | not_found_error | 404 | The template asset (logo, image or font) does not exist in this company or was removed. |
pdf_template_default_replacement_required | invalid_request_error | 422 | Archiving the template would leave defaults or associations without a template, and no replacement was given for them. |
pdf_template_not_found | not_found_error | 404 | The PDF template does not exist in this company. |
pdf_template_precondition_failed | conflict_error | 412 | The ETag sent in If-Match no longer matches the stored template, which was modified after you read it. |
pdf_template_precondition_required | invalid_request_error | 428 | Changing the template requires stating the version it is based on, and none was sent. |
pdf_template_version_conflict | conflict_error | 409 | The template was modified after you read it, so the expected_version you sent is stale. |
preparation_required | conflict_error | 409 | Prepare the PDF for this presentation before requesting it. |
Pricing
| Code | Type | HTTP | Description |
|---|---|---|---|
duplicate_price_list_name | invalid_request_error | 422 | Another price list in the company already uses that name, which must be unique within the tenant. |
inactive_price_list | invalid_request_error | 422 | The price list is inactive and may only be read to explain historical documents, not selected for a new operation. |
invalid_price_list_item | invalid_request_error | 422 | The price-list entry has an incompatible target, amount or unit, or duplicates the same product, variant and presentation within the list. |
price_list_in_use | invalid_request_error | 422 | The price list is assigned to clients or drafts, and deleting it would leave those price references without their source. |
price_list_item_not_found | not_found_error | 404 | The item does not exist in the price list: it was already removed or the identifier belongs to another price list. |
price_list_not_found | not_found_error | 404 | The identifier does not resolve to any price list of the authenticated company. |
Products
| Code | Type | HTTP | Description |
|---|---|---|---|
duplicate_pack_component | invalid_request_error | 422 | The same product, variant, presentation or configuration appears more than once in the pack. |
duplicate_promotion_item | invalid_request_error | 422 | The same article appears more than once in the offer, and each article can have only one price rule. |
gross_weight_not_allowed | invalid_request_error | 422 | This item cannot carry a gross transport weight: services have no weight, products and variants whose base unit is a mass unit (KGM, GRM) already weigh their quantity, and a variable-measure presentation is weighed on each line. |
invalid_gross_weight | invalid_request_error | 422 | The gross transport weight is not a number, is zero or negative, has more than 4 decimals or exceeds the column ceiling. On a goods line of a transport control document, also when the quantity times the weight per unit gives a line weight that rounds to 0 kg or exceeds that ceiling. |
invalid_pack_component | invalid_request_error | 422 | A component cannot be part of a pack, for example a product sold by real weight, whose price is only known at the scale. |
invalid_pack_image | invalid_request_error | 422 | The uploaded file is not a usable pack image: it is not a JPG, PNG, WebP or GIF image, it exceeds the maximum size or it could not be read. |
invalid_pack_pricing | invalid_request_error | 422 | The pack price is not valid for its mode: a missing or out-of-range value, more than two decimals, or a discount that equals or exceeds the price of the products separately. |
invalid_pack_status_transition | invalid_request_error | 422 | The requested status change is not allowed from the current pack status, for example activating a pack without sales channels or restoring one whose composition is blocked. |
invalid_promotion | invalid_request_error | 422 | A field of the offer breaks one of its rules: the name, the text shown on the web, the dates, the time zone, the channels or the list of articles. |
invalid_promotion_item | invalid_request_error | 422 | An article of the offer is not valid: its target, its mode, its basis or its value breaks a rule. |
pack_composition_too_small | invalid_request_error | 422 | A pack needs at least two components, or a single counted product with a quantity of 2 or more. |
pack_group_not_contiguous | invalid_request_error | 422 | The lines of the same pack are not consecutive in the document. Another line sits between them. |
pack_image_limit_reached | invalid_request_error | 422 | The pack already has the maximum of 5 images. |
pack_in_use | invalid_request_error | 422 | The pack is referenced by issued documents, so deleting it would break their composition. |
pack_line_locked | invalid_request_error | 422 | A line that belongs to a pack group cannot change its product, quantity, unit price or discount. |
pack_lines_must_be_expanded | invalid_request_error | 422 | The lines of a pack cannot be built by hand. The server splits the price among the components of the pack and sets the group data itself. |
pack_not_found | not_found_error | 404 | The identifier does not resolve to any pack of the authenticated company. |
pack_not_sellable | invalid_request_error | 422 | The pack cannot be added to a document: it is archived, inactive, out of its availability dates, or one of its components is inactive. |
pack_price_allocation_impossible | invalid_request_error | 422 | The pack price cannot be split among its components because they have no price when bought separately. |
pack_price_unreachable | invalid_request_error | 422 | The requested price including VAT cannot be reached exactly because VAT is rounded line by line. |
pack_print_mode_not_allowed | invalid_request_error | 422 | The only print mode is full_breakdown: every product of the pack is printed as a regular line with the pack name. |
pack_snapshot_invalid | invalid_request_error | 422 | The pack snapshot sent with the document line is unsigned, altered or malformed. |
product_in_use | invalid_request_error | 422 | The product is referenced by issued documents or by other catalogue entries, and removing it would leave those references dangling. |
product_not_found | not_found_error | 404 | The identifier does not resolve to any product of the authenticated company. |
promotion_not_found | not_found_error | 404 | The identifier does not resolve to any offer of the authenticated company. |
promotion_read_only | invalid_request_error | 422 | The offer has ended or been cancelled, so it is read-only and accepts no further changes. |
promotion_started | invalid_request_error | 422 | The offer has already started and is part of the price history. A started offer only allows changing its end date and cannot be deleted. |
sku_already_exists | conflict_error | 409 | Another product of the company already uses that SKU, and the SKU identifies the item uniquely in the catalogue. |
slug_already_exists | conflict_error | 409 | The slug is already used, as current or previous slug, by another product or pack of the company. |
Proformas
| Code | Type | HTTP | Description |
|---|---|---|---|
invalid_expiry_date | invalid_request_error | 422 | The expiry date is earlier than the issue date, or more than 365 days after it. |
invalid_proforma_id | invalid_request_error | 400 | The pro forma reference received is not a valid identifier, usually because an internal value replaced the public id. |
invalid_proforma_number | invalid_request_error | 422 | The pro forma number does not follow the canonical numbering format of its series. |
invalid_proforma_status | invalid_request_error | 422 | The value sent as status is outside the catalogue draft, accepted, rejected, expired, invoiced, cancelled. |
invalid_proforma_uuid | invalid_request_error | 400 | The pro forma identifier in the path or in the payload is not a valid UUID. |
proforma_already_accepted | invalid_request_error | 422 | The customer already accepted the pro forma, and acceptance is registered once. |
proforma_already_rejected | invalid_request_error | 422 | The pro forma is already marked as rejected. |
proforma_cannot_be_accepted | invalid_request_error | 422 | Acceptance does not apply from the current state: an invoiced, cancelled or expired pro forma no longer admits it. |
proforma_cannot_be_rejected | invalid_request_error | 422 | Rejection does not apply from the current state: once invoiced, cancelled or expired, the pro forma is closed. |
proforma_cannot_be_sent | invalid_request_error | 422 | Sending by email does not apply to a pro forma in a terminal state: there is no live offer to deliver. |
proforma_invalid_status_transition | invalid_request_error | 422 | The target status is unreachable from the current one: a draft can be accepted, cancelled or expire; an accepted pro forma can be invoiced, rejected or expire; invoiced, cancelled and expired are terminal. |
proforma_not_convertible_in_current_state | invalid_request_error | 422 | Converting into an invoice requires the customer to have accepted the pro forma; from any other state there is no agreement to bill. |
proforma_not_deletable_in_current_state | invalid_request_error | 422 | Only a draft pro forma can be deleted. Once it has been accepted, rejected or invoiced, it is part of the commercial trail. |
proforma_not_draft | invalid_request_error | 422 | The operation only makes sense while the pro forma is a draft, and this one has already moved on. |
proforma_not_editable_in_current_state | invalid_request_error | 422 | Only a draft pro forma admits editing. Once it is accepted, rejected, expired, invoiced or cancelled, its content is settled. |
proforma_not_found | not_found_error | 404 | The identifier does not resolve to any pro forma of the authenticated company. |
proforma_requires_at_least_one_line | invalid_request_error | 422 | The pro forma has no lines, so there is no amount to put in front of the customer. |
public_link_expires_at_exceeds_max_days | invalid_request_error | 422 | The requested expiry for the public link goes beyond the maximum window your plan allows for shared documents. |
Expenses
| Code | Type | HTTP | Description |
|---|---|---|---|
attachment_invalid_filename | invalid_request_error | 422 | The file name is not usable: it is empty, it carries path components, or it exceeds 200 characters. |
attachment_mime_not_allowed | invalid_request_error | 422 | The file type is outside the accepted set: PDF, PNG, JPEG, XML and HTML. |
attachment_missing | not_found_error | 404 | The expense exists but carries no attached file, so there is nothing to download. |
attachment_too_large | invalid_request_error | 422 | The file exceeds the maximum size allowed for a document attachment. |
cannot_attach_to_cancelled_purchase_invoice | invalid_request_error | 422 | The expense is cancelled, and attaching documents to a cancelled record would alter closed documentation. |
invalid_purchase_invoice_id | invalid_request_error | 400 | The expense reference received is not a valid identifier, usually because an internal value replaced the public id. |
invalid_purchase_invoice_number | invalid_request_error | 422 | The invoice number is empty or does not fit the accepted format. On a supplier invoice the number is the one the supplier printed, not one Factuarea generates. |
invalid_purchase_invoice_uuid | invalid_request_error | 400 | The expense identifier in the path or in the payload is not a valid UUID. |
operation_regime_invalid | invalid_request_error | 422 | The operation regime is outside the catalogue general, intracomunitaria, importacion_exportacion, isp. |
purchase_invoice_already_exists | conflict_error | 409 | That supplier already has an expense registered with the same number. The pair supplier plus number identifies the document uniquely and prevents recording an expense twice. |
purchase_invoice_not_deletable_in_current_state | invalid_request_error | 422 | Only draft and cancelled expenses can be deleted. A pending or paid one is part of the expense ledger. |
purchase_invoice_not_draft | invalid_request_error | 422 | The operation only applies while the expense is a draft, and this one has already been registered. |
purchase_invoice_not_editable_in_current_state | invalid_request_error | 422 | Only a draft expense can be edited. Once registered as pending, paid or cancelled, its content backs an accounting entry. |
purchase_invoice_not_found | not_found_error | 404 | The identifier does not resolve to any expense of the authenticated company. |
purchase_invoice_requires_at_least_one_line | invalid_request_error | 422 | The expense has no lines, so there is no amount nor deductible VAT to record. |
Expense scanner
| Code | Type | HTTP | Description |
|---|---|---|---|
duplicate_override_reason_required | invalid_request_error | 422 | A valid reason to proceed despite the duplicate is missing. |
duplicate_resolution_required | invalid_request_error | 422 | A possible duplicate requires review. |
invalid_inbound_signature | authentication_error | 401 | The inbound email signature could not be authenticated. |
invalid_purchase_scan_transition | invalid_request_error | 422 | The current scan status does not allow this transition. |
module_upgrade_required | authorization_error | 403 | The current plan does not include the requested OCR capability. |
ocr_company_daily_quota_exceeded | rate_limit_error | 429 | The company has exhausted its daily OCR quota. |
ocr_company_quota_exceeded | rate_limit_error | 429 | The company has exhausted its monthly OCR quota. |
purchase_scan_already_converted | conflict_error | 409 | The scan is already linked to an expense. |
purchase_scan_not_found | not_found_error | 404 | The scan does not exist or does not belong to the active company. |
purchase_scan_retry_not_allowed | invalid_request_error | 422 | The scan cannot be retried in its current status. |
purchase_scan_review_incomplete | invalid_request_error | 422 | Required data is missing or the reviewed amounts do not reconcile. |
purchase_scan_source_unavailable | invalid_request_error | 422 | The scan original was purged or is no longer available in secure storage. |
scan_batch_too_large | invalid_request_error | 413 | The batch exceeds the permitted total size. |
scan_decompression_limit_exceeded | invalid_request_error | 413 | The file exceeds the safe decompression limit. |
scan_file_too_large | invalid_request_error | 413 | A file exceeds the 20 MiB limit. |
scan_page_limit_exceeded | invalid_request_error | 413 | The document exceeds the configured page limit. |
scan_pixel_limit_exceeded | invalid_request_error | 413 | The document resolution exceeds the safe processing limit. |
scan_storage_unavailable | service_unavailable_error | 503 | Secure storage for the original is unavailable. |
scanner_admin_required | authorization_error | 403 | The action requires scanner administration permissions. |
stale_scan_version | conflict_error | 409 | The scan has changed since it was last read. |
unsafe_scan_file | invalid_request_error | 422 | The original failed security inspection. |
unsupported_purchase_currency | invalid_request_error | 422 | The document currency is not supported for conversion. |
unsupported_purchase_document_type | invalid_request_error | 422 | The original is a delivery note, order, quote, proforma or another document that does not substantiate a fiscal expense. |
unsupported_scan_format | invalid_request_error | 422 | The actual file format is unsupported. |
validation_failed | invalid_request_error | 422 | The scan data does not meet the stated constraints. |
Quotes
| Code | Type | HTTP | Description |
|---|---|---|---|
quote_already_accepted | invalid_request_error | 422 | The quote was already approved, and approval is registered once. |
quote_already_rejected | invalid_request_error | 422 | The quote is already marked as rejected. |
quote_cannot_be_sent | invalid_request_error | 422 | The quote is rejected, converted, expired or cancelled: it is no longer a live offer to deliver. |
quote_expired | invalid_request_error | 422 | The quote passed its validity date, so the offered conditions are no longer binding and it cannot be approved or converted as is. |
quote_not_found | not_found_error | 404 | The identifier does not resolve to any quote of the authenticated company. |
Rate Limit
| Code | Type | HTTP | Description |
|---|---|---|---|
account_probation_limit_exceeded | rate_limit_error | 429 | The company is inside its NEW-ACCOUNT PROBATION window, and the ceiling that rejected this call comes from the ACCOUNT'S AGE, not from its plan. A freshly created account starts with a reduced allowance that widens on its own as the account matures. |
company_monthly_quota_exceeded | rate_limit_error | 429 | The company used up the monthly volume its plan grants to all of its keys together. |
company_rate_limit_exceeded | rate_limit_error | 429 | The company exceeded the per-minute rate its plan grants to all of its keys together, not the rate of a single key. |
email_delivery_circuit_open | rate_limit_error | 429 | Email sending is temporarily CUT, either by a provider incident or by a delivery problem of this company. It is not a quota: it is a safety cut so sending reputation is not burnt further while delivery keeps failing. |
email_recipient_budget_exceeded | rate_limit_error | 429 | The company ran out of DISTINCT RECIPIENT budget for the window. This is not a request limit: it counts mailboxes reached, so neither splitting the send across more calls nor using another credential changes anything. |
import_row_quota_exceeded | rate_limit_error | 429 | The newly admitted import rows would exceed the plan’s monthly row allowance. |
monthly_quota_exceeded | rate_limit_error | 429 | The company exhausted the monthly call quota its plan includes. |
pdf_generation_budget_exceeded | rate_limit_error | 429 | The hourly budget of PDF RENDER WORK is exhausted. This is not a request limit: it counts renders against the Chrome pool shared by every tenant, so neither spreading the calls nor using another credential changes anything. The subcode says which of the two budgets ran out — company_budget (the whole company) or document_budget (this single document, while the rest keep generating). |
portfolio_monthly_quota_exceeded | rate_limit_error | 429 | The portfolio MONTHLY quota is exhausted. It is counted over the whole account — all its tax IDs together — so one tax ID's consumption exhausts everyone's. |
portfolio_rate_limit_exceeded | rate_limit_error | 429 | The per-minute ceiling you hit belongs to the PORTFOLIO — an account with two or more real tax IDs, where the requests of all its credentials add up whichever tax ID they reach — not to this credential nor to this company. That is why neither spreading traffic across credentials nor adding another tax ID to the account changes anything: everything keeps counting in the same bucket. |
rate_limit_exceeded | rate_limit_error | 429 | The key sent more requests than its rate allows in the current window. |
upload_in_flight_budget_exceeded | rate_limit_error | 429 | The company has too many bytes crossing the temporary disk at once (tabular imports and their previews, UBL, OCR and backup restore). This is a budget of bytes IN FLIGHT, not of stored space: it consumes no request bucket and does not appear in the rate-limit headers. |
Recurring Invoices
| Code | Type | HTTP | Description |
|---|---|---|---|
invalid_frequency_interval | invalid_request_error | 422 | The interval is lower than 1, so the recurrence would never advance to a next run. |
invalid_frequency_type | invalid_request_error | 422 | The frequency is outside the catalogue daily, weekly, biweekly, monthly, bimonthly, quarterly, semiannual, annual, custom. |
invalid_holiday_handling | invalid_request_error | 422 | The holiday policy is outside the catalogue skip, before, after, same. |
invalid_recurring_invoice_id | invalid_request_error | 400 | The recurrence reference received is not a valid identifier, usually because an internal value replaced the public id. |
invalid_recurring_invoice_uuid | invalid_request_error | 400 | The recurrence identifier in the path or in the payload is not a valid UUID. |
invalid_recurring_payment_terms_template | invalid_request_error | 422 | The payment schedule template of the recurrence, applied to every invoice it generates, is not valid. |
invalid_recurring_presentation_policy | invalid_request_error | 422 | The presentation policy of the recurrence, which sets how the invoices it generates are presented, has an invalid value. |
recurring_already_active | invalid_request_error | 422 | The recurrence is already running, so there is nothing to activate. Legacy code kept for compatibility: current endpoints report this as recurring_invoice_already_active. |
recurring_invoice_already_active | invalid_request_error | 422 | The recurrence is already running. |
recurring_invoice_already_cancelled | invalid_request_error | 422 | The recurrence was already cancelled, and cancellation is terminal. |
recurring_invoice_already_paused | invalid_request_error | 422 | The recurrence is already paused, so pausing it again changes nothing. |
recurring_invoice_cancelled_cannot_resume | invalid_request_error | 422 | A cancelled recurrence cannot be resumed: cancellation closes it for good, unlike a pause. |
recurring_invoice_cannot_run | invalid_request_error | 422 | The recurrence cannot generate an invoice right now: it is not running, its cycle is over, or it lacks the data an invoice needs. error.message states the specific reason. |
recurring_invoice_completed_cannot_resume | invalid_request_error | 422 | A completed recurrence cannot be resumed or activated: it has already used up its occurrences or passed its end date, so no generation is left pending. |
recurring_invoice_has_generated_invoices | invalid_request_error | 422 | The recurrence already produced invoices, and those invoices depend on it for their traceability. |
recurring_invoice_not_found | not_found_error | 404 | The identifier does not resolve to any recurrence of the authenticated company. |
recurring_invoice_requires_at_least_one_line | invalid_request_error | 422 | The recurrence has no lines, so every generated invoice would come out empty. |
recurring_not_active | invalid_request_error | 422 | The operation needs a running recurrence and this one is paused, completed or cancelled. Legacy code kept for compatibility with older integrations. |
recurring_presentation_activation_changed | conflict_error | 409 | The company switched its presentation system on or off twice in a row while the recurring invoice was being generated. The generation stopped without writing anything. |
recurring_presentation_policy_precondition_required | invalid_request_error | 428 | The change to the presentation policy did not state which version it is based on. |
recurring_presentation_policy_version_conflict | conflict_error | 409 | The presentation policy of the recurrence changed after you read it. |
recurring_presentation_unavailable | invalid_request_error | 422 | When a generation of the recurrence ran, the presentation it is configured to use was not available, so the invoice could not be generated. details.reason says what was missing. |
Request
| Code | Type | HTTP | Description |
|---|---|---|---|
business_rule_violation | invalid_request_error | 422 | A domain invariant rejected the operation. This code carries the family; error.subcode names the concrete rule and error.message explains it. |
conflicting_pagination_params | invalid_request_error | 422 | starting_after and ending_before travelled in the same request. They walk the collection in opposite directions, so only one of them can apply. |
external_id_already_exists | conflict_error | 409 | The external_id you use to reconcile with your own system is already assigned to another object of the same type in this company. |
invalid_param_format | invalid_request_error | 422 | A legacy form request rejected the shape of a value. Migrated endpoints report the same situation as parameter_invalid_format or parameter_invalid_integer. |
invalid_param_value | invalid_request_error | 422 | A legacy form request rejected the value of a field. Migrated endpoints report the same situation as parameter_invalid_enum or parameter_invalid_range. |
invalid_status_transition | invalid_request_error | 422 | The requested state is not reachable from the state the document is in right now. |
length_required | invalid_request_error | 411 | A request with a body arrived using chunked transfer encoding, without declaring its size. The API needs the length up front to reject oversized payloads before buffering them. |
metadata_too_many_keys | invalid_request_error | 422 | The metadata object exceeds the limit of 50 keys per resource. |
metadata_value_too_long | invalid_request_error | 422 | One value of metadata exceeds 500 characters once serialised to text. |
method_not_allowed | invalid_request_error | 405 | The path exists but does not accept the HTTP verb used. |
missing_required_param | invalid_request_error | 422 | A legacy form request found a required field missing. Endpoints already migrated to the canonical parsers report the same situation as parameter_missing. It is also returned for an invoice, quote, proforma, delivery note or recurring invoice line sent without tax_rate when neither its product has an assigned tax nor your company has a default VAT for that document type: error.param is lines.N.tax_rate and error.line_index is the zero-based position of that line. POST /v1/companies/{company}/invoices also returns it when you ask for the email sending (options.send_automatically) and there is no possible recipient — no client, or a client with no email, and no options.send_to: error.param is options.send_to and no invoice is created. |
parameter_invalid | invalid_request_error | 422 | A value object built from the payload rejected the value it received. error.subcode names which one — tax code, country code, rate, and so on. |
parameter_invalid_boolean | invalid_request_error | 400 | A parameter that must be a boolean received a value outside the accepted representations (true/false, 1/0). |
parameter_invalid_cursor | invalid_request_error | 400 | The starting_after or ending_before cursor is not a valid UUID, so it cannot point at any row of the collection. |
parameter_invalid_empty | invalid_request_error | 400 | A parameter arrived with an empty value: an in filter with no items, a comparison with nothing after the operator, or an equality filter with an empty string. |
parameter_invalid_enum | invalid_request_error | 400 | The value falls outside the closed set the parameter accepts. On listings it also covers a filter operator other than eq, gte, lte, gt, lt, in or contains, and it is the main code (400). On operations that validate a form or a query parameter with rules (for example format on the invoice PDFs) it arrives as an entry of error.errors[], with its allowed_values, inside a 422 invalid_param_value. |
parameter_invalid_format | invalid_request_error | 400 | The value has the right type but not the shape the parameter requires: a date, an identifier pattern or a header such as Factuarea-Version. |
parameter_invalid_integer | invalid_request_error | 400 | A parameter that must be a whole number received something that cannot be parsed as one, such as limit=abc. |
parameter_invalid_iso8601 | invalid_request_error | 400 | A range filter (gte, lte, gt, lt) received a value that is neither numeric nor an ISO 8601 date. |
parameter_invalid_range | invalid_request_error | 400 | A numeric parameter fell outside its accepted bounds. The usual case is limit, which must be between 1 and 100. |
parameter_invalid_string | invalid_request_error | 400 | A parameter that must be text received an array, an object or a value that cannot be read as a string. |
parameter_invalid_url | invalid_request_error | 400 | A field that must hold an absolute URL received a value that is not one, usually because the scheme or the host is missing. |
parameter_invalid_uuid | invalid_request_error | 400 | An identifier field received a value that is not a valid UUID. Every v1 resource id is a UUID. |
parameter_invalid_value | invalid_request_error | 422 | The value is syntactically correct but not admissible for this resource: outside the canonical catalogue of the field, or inconsistent with the rest of the payload. |
parameter_missing | invalid_request_error | 400 | The endpoint requires a parameter that the request did not carry. error.param names it. |
parameter_unknown | invalid_request_error | 400 | The request carries a parameter the endpoint does not accept: a filter outside its allowlist, a sort field that is not sortable, the offset-style page — v1 paginates by cursor — or a header that has been retired from v1. |
payload_too_large | invalid_request_error | 413 | The request body exceeds the accepted size: 1 MB as a rule, 6 MB on the endpoints that accept files. |
profile_not_found | not_found_error | 404 | The {company} path segment names a company that does not exist or is not within the credential's NIF scope. Both cases answer the same so that the API never reveals companies of other accounts. |
resource_already_exists | conflict_error | 409 | Creating the object would duplicate one that already exists under a unique key — tax id, SKU, external id. error.details.existing_resource_id points at the object that already holds the value. |
resource_conflict | conflict_error | 409 | The operation collided with the current state of the resource and no more specific conflict code applies. |
resource_immutable | invalid_request_error | 422 | The object is closed to changes for this operation: its state or its accounting record forbids modifying it. |
resource_locked | conflict_error | 409 | Another operation holds the resource until it finishes: concurrent writes on the same object are serialised instead of interleaved. On POST /v1/companies/{company}/invoices with external_id, another request with the SAME external_id is still in progress and had not finished after waiting 20 seconds. |
resource_not_deletable | invalid_request_error | 422 | The object exists but its state or its dependants block the deletion. In bulk deletions this is the per-row code of every entry that could not be removed. |
resource_not_found | not_found_error | 404 | The identifier resolves to nothing visible to the authenticated company. Objects belonging to another company answer exactly the same way, by design. |
route_not_found | not_found_error | 404 | The path does not match any v1 endpoint. It is usually a typo, a missing /v1 prefix, a path from a different area of the API, or the flat form of a route that the breaking window moved under the company or account segment; in that last case error.subcode is legacy_route_moved. |
unknown_filter | invalid_request_error | 422 | A listing received a filter it does not know. The canonical v1 parsers report this as parameter_unknown; this code survives for endpoints that have not migrated yet. |
unsupported_api_version | invalid_request_error | 400 | The Factuarea-Version header is well formed but names a version outside the supported set. |
unsupported_media_type | invalid_request_error | 415 | A request with a body declared a Content-Type other than application/json. |
Series
| Code | Type | HTTP | Description |
|---|---|---|---|
cannot_archive_last_default_series | invalid_request_error | 422 | The series is the only active one for its document type. Archiving it would leave the company with no numbering available and freeze that kind of document. |
document_type_required_for_ambiguous_code | invalid_request_error | 422 | That series code exists for more than one document type, so on its own it does not identify a single series. |
invalid_series_code | invalid_request_error | 422 | The series code is empty, too long, or carries characters that do not belong in a fiscal prefix. |
invalid_series_name | invalid_request_error | 422 | The series name is empty or exceeds the allowed length. |
invalid_series_number | invalid_request_error | 422 | The starting number is not valid: it is not a positive integer, or it falls at or below the last number already issued, which would re-issue numbers already in use. |
invalid_series_template_assignment | invalid_request_error | 422 | The PDF template assignment sent for the series is inconsistent: the selection or its version is not valid. |
invalid_series_uuid | invalid_request_error | 400 | The series identifier in the path or in the payload is not a valid UUID. |
invalid_series_year | invalid_request_error | 422 | The fiscal year is not a valid four-digit year for a numbering series. |
monthly_requires_month_segmented_format | invalid_request_error | 422 | The counter resets monthly but the numbering mask does not segment by month, so two months would start on the same correlative and produce duplicate numbers within the year. |
series_already_archived | invalid_request_error | 422 | The series was already archived, and archiving is not repeated: a second call means the client is out of sync with the real state. |
series_code_immutable_with_documents | invalid_request_error | 422 | Changing the prefix of a series that already issued documents would retroactively rewrite their fiscal identifier, while customers and AEAT hold the original number. |
series_default_kind_change | invalid_request_error | 422 | The series is the default one of its purpose (invoice_kind): the default series is per company, document type and purpose, so changing its purpose would leave that purpose without a default series. |
series_format_immutable_with_documents | invalid_request_error | 422 | The numbering mask of a series can be changed until the first document is issued: after that, the PDF and the AEAT record of the issued documents carry the number in the original format. |
series_has_documents | invalid_request_error | 422 | The series already numbered documents, so it cannot be removed: the correlative sequence has to stay auditable. |
series_immutable | invalid_request_error | 405 | A series is never deleted through the API: it keeps the documents it numbered and its code is not released. PUT and DELETE are not operations on a series. |
series_initial_number_creates_gap | invalid_request_error | 422 | The starting number jumps beyond the next natural correlative while documents already exist for the current year, and that gap in the sequence is not acceptable to AEAT. |
series_invoice_kind_invalid | invalid_request_error | 422 | The series purpose is outside the catalogue complete, simplified, corrective, simplified_corrective, or it was sent for a series that is not an invoice series. |
series_invoice_kind_locked | invalid_request_error | 422 | The purpose of a series (invoice_kind) is fixed on creation and stops being editable as soon as the series has any invoice: changing it would mix invoice types in one correlative numbering. |
series_invoice_kind_mismatch | invalid_request_error | 422 | Invoice series have a fixed purpose (invoice_kind): complete for complete invoices, simplified for simplified invoices, corrective for corrective invoices and simplified_corrective for corrective invoices of simplified invoices. An invoice is only numbered in a series of its own purpose (RD 1619/2012 arts. 6.1.a, 7.1.a and 15), and the series you chose has another one. |
series_locked_by_verifactu | invalid_request_error | 422 | At least one invoice of the series holds a billing record accepted by AEAT, which freezes the prefix, the year and the numbering base of the series. |
series_not_found | not_found_error | 404 | The identifier does not resolve to any numbering series of the authenticated company. |
series_template_access_denied | authorization_error | 403 | The credential or user does not have permission to change the PDF template of this series. |
series_template_incompatible | invalid_request_error | 422 | The template does not support the document type, the purpose (invoice_kind) or the number format of the series. |
series_template_precondition_failed | conflict_error | 412 | The ETag sent in If-Match no longer matches the series template resource, which changed after you read it. |
series_template_precondition_required | invalid_request_error | 428 | The change to the series template did not state the version or resource precondition it is based on. |
series_template_unavailable | invalid_request_error | 422 | The template is archived or otherwise not selectable for this company, so it cannot be assigned to the series. |
series_template_version_conflict | conflict_error | 409 | The PDF template assignment of the series changed after you read it. |
series_type_invalid | invalid_request_error | 422 | The document type of the series is outside the catalogue invoice, quote, delivery_note, proforma, purchase_invoice, recurring_invoice. |
series_year_locked | invalid_request_error | 422 | The series already issued documents in its current year. Moving the year would leave those documents pointing at an empty year while their taxable base sits in another. |
Server
| Code | Type | HTTP | Description |
|---|---|---|---|
dependency_unavailable | service_unavailable_error | 503 | An external service the operation relies on did not answer in time. |
face_transmission_failed | api_error | 502 | The FACe platform — the public administration entry point — was unreachable or answered with a fault. The failure is upstream, not in your request. |
facturae_signing_failed | api_error | 500 | The XAdES signature of the Facturae file could not be produced, usually because the signing certificate is unusable at that moment. |
internal_error | api_error | 500 | Something broke on our side while processing the request. The condition is not caused by your payload. |
maintenance | service_unavailable_error | 503 | The platform is in a maintenance window and writes are held back on purpose. |
pdf_generation_failed | service_unavailable_error | 503 | The rendering service could not produce the PDF. The document and its data are intact — what failed is the file. |
register_sealing_failed | api_error | 500 | The cryptographic sealing of the record did not complete, so the closure was left unsigned rather than sealed with a broken signature. |
send_failed | api_error | 500 | The document was not delivered by email: the mail provider rejected the message or was unreachable. |
service_unavailable | service_unavailable_error | 503 | The service, or a dependency it needs, is temporarily unable to answer. |
Storage
| Code | Type | HTTP | Description |
|---|---|---|---|
storage_quota_exceeded | payment_required_error | 402 | The account has reached its maximum usage. |
Task Integrations
| Code | Type | HTTP | Description |
|---|---|---|---|
forge_account_link_rejected | invalid_request_error | 422 | Only personal GitHub accounts can be linked. GitLab and Gitea do not use linked accounts: they connect with the access token of the project integration. |
forge_account_not_linked | invalid_request_error | 422 | The operation acts on your behalf in the forge —for example, to list your GitHub repositories— and you have not linked your account on that forge to your user yet. |
forge_credentials_rejected | invalid_request_error | 422 | The GitLab or Gitea instance rejects the given address or credential. The subcode says why: not_a_forge_instance, redirected, repository_not_found, insufficient_permissions or unauthorized. |
forge_oauth_state_invalid | invalid_request_error | 422 | The forge link could not be completed: the authorisation state has expired, was already used, is not valid or belongs to another user or company. |
forge_repository_access_denied | authorization_error | 403 | Your linked GitHub account does not allow connecting that repository, or the repository does not exist; the answer is the same in both cases so that other people's repositories are not revealed. |
forge_repository_bound_elsewhere | conflict_error | 409 | The repository is already connected to another active project of the company. A repository feeds a single project, so that each issue or pull request ends up in a single task. |
forge_secret_rotation_not_supported | invalid_request_error | 422 | This integration has no webhook secret of its own to rotate: GitHub integrations sign with the GitHub App secret, and rotation only exists for GitLab and Gitea integrations. |
forge_token_required | invalid_request_error | 422 | The forge instance URL is being changed without a new token. The stored token is never sent to an address other than the one it was issued for, so that it does not end up on a foreign server. |
forge_webhook_signature_invalid | authentication_error | 401 | The forge webhook delivery could not be authenticated: the signature does not match the integration secret, or the integration does not exist. No event was processed. |
forge_workflow_rule_column_invalid | invalid_request_error | 422 | The rule's target column does not belong to the integration's project; a non-existent column, one from another project or one from another company all answer the same. |
forge_workflow_rule_not_found | not_found_error | 404 | The rule that moves tasks between columns on a forge event (for example, when a pull request is merged) does not exist or belongs to another company; both cases answer the same. |
github_app_not_configured | invalid_request_error | 422 | The GitHub integration is not available on this server because its administrator has not configured the GitHub App. It is not a problem with your account or your permissions. |
import_credentials_rejected | invalid_request_error | 422 | The import source system rejected the supplied credentials with an unauthorised or forbidden response. Nothing was imported. |
import_run_already_active | conflict_error | 409 | An import from the same source into the same target is already running. Two simultaneous imports would create duplicate tasks, so the second one is not started. |
integration_destination_not_allowed | invalid_request_error | 422 | The company egress policy does not allow connecting to that address: for security, private or internal destinations are blocked unless the company has allowed them. The error does not repeat the rejected URL. |
project_integration_already_connected | conflict_error | 409 | The project already has an integration of that type, or is already connected to another repository. Each project accepts one integration per type, so that events are not duplicated. |
project_integration_not_found | not_found_error | 404 | The project integration does not exist or belongs to another company; both cases answer the same. Forge and chat integrations are managed only from the web application, not from the v1 API. |
task_import_run_not_found | not_found_error | 404 | The given import does not exist or belongs to another company; both cases answer the same. Each import has its own identifier, different from the target project's. |
Tasks
| Code | Type | HTTP | Description |
|---|---|---|---|
bulk_task_selection_too_large | invalid_request_error | 422 | The bulk operation includes more tasks than a single batch allows (200 by default; the message states the current ceiling). It is not a request limit or a plan limit: it bounds what is processed at once. |
column_has_tasks | conflict_error | 409 | The column you are trying to delete still holds tasks and the request does not say where to move them. To avoid leaving tasks without a place on the board, the deletion is rejected and nothing was changed. |
column_slug_in_use | conflict_error | 409 | Another column of the same project already has an equivalent name. The comparison uses the identifier derived from the name, so two names that differ only in case or punctuation still collide. |
column_slug_reserved | invalid_request_error | 422 | The column name translates into the identifier planned or archived, which are reserved for the statuses of tasks that sit outside the board. Such a column would be indistinguishable from those statuses. |
invalid_custom_field_definition | invalid_request_error | 422 | The custom field definition is not valid: name outside 1 to 60 characters, unknown type, required field without a default value, options on a type that does not accept them, type change after creation, removing an option that tasks use, or an incomplete reordering. error.param points at the exact item. |
invalid_custom_field_value | invalid_request_error | 422 | The value does not fit the custom field type —for example, text in a numeric field or an option that is not in the list— or the field does not belong to the task's project. |
invalid_move_target_column | invalid_request_error | 422 | The column given to receive the tasks is not a valid target: it does not exist, belongs to another project or is the very column being deleted. The deletion was not performed. |
invalid_task_key | invalid_request_error | 422 | The task key is not shaped KEY-N —project key, hyphen and number, such as WEB-42— or the task number is not a positive integer. |
invalid_task_reference | invalid_request_error | 422 | A task referenced in the request body does not exist or belongs to another company; both cases answer the same. error.param names the field that held the reference. |
invalid_task_schedule | invalid_request_error | 422 | The task dates are not consistent: the start date is later than the due date, or one of them does not exist in the calendar (for example, 30 February). |
invalid_task_status | invalid_request_error | 422 | The task target is not valid: the status does not exist, the transition is not allowed, a column and a status are sent together, the column is not in the task's project, or a column is given for a planned or archived task. A task on the board always has a column and one outside it never does. |
invalid_time_entry_period | invalid_request_error | 422 | The time entry period is not valid: the end is before the start, it lasts more than 24 hours, the start is more than one day in the future, a date is invalid, the end of a closed entry is being removed, or the times of a still-running entry are being changed. |
limit_exceeded | payment_required_error | 402 | The company has reached its plan limit of invoices or annual documents; the message says which. In the v1 API it is emitted by time invoicing (POST /v1/companies/{company}/projects/{project}/time-invoices), which checks it before creating anything: no draft invoice was generated and no hours were marked as invoiced. |
linked_entity_not_found | not_found_error | 404 | The entity to link does not exist, belongs to another company or belongs to a module the company has not subscribed to; all three cases answer the same. It happens when linking (POST /v1/companies/{company}/tasks/{task}/entity-links) and also when creating a task with entity_link in POST /v1/companies/{company}/tasks: in that case the task is NOT created. |
project_archived | invalid_request_error | 422 | The project is archived and accepts neither new tasks nor tasks being moved into it. Archiving freezes the project without deleting it. |
project_column_not_found | not_found_error | 404 | The column does not exist, belongs to another project or belongs to another company; all three cases answer the same. A column is only addressable inside the project that contains it. |
project_has_no_columns | invalid_request_error | 422 | The task is being placed on the board, but the project has no column to put it in. An active task always lives in a column. |
project_key_in_use | conflict_error | 409 | The short key is already used by another project of the company, or is still reserved as the former key of a project that changed it. The key names the tasks (WEB-42), so it cannot repeat within the company. |
project_not_found | not_found_error | 404 | There is no project with that identifier or key in the authenticated company. A project belonging to another company answers exactly the same, so the response never reveals whether it exists elsewhere. |
required_custom_field_missing | invalid_request_error | 422 | A value is missing for a custom field that the project declares as required; the message names the field. A required field cannot be left empty. |
task_already_in_project | invalid_request_error | 422 | The task is being moved to the project it is already in, so there is no move to make. |
task_assignee_not_member | invalid_request_error | 422 | The user given as assignee is not a member of the company. A non-existent user, one from another company or one without membership all answer the same, so that other accounts are not revealed. |
task_attachment_not_found | not_found_error | 404 | The attachment does not exist, belongs to another task or belongs to another company; all three cases answer the same. A deleted attachment can no longer be read or downloaded. |
task_attachment_rejected | invalid_request_error | 422 | The file is not accepted as an attachment: it is empty, exceeds 10 MB, or its real type —detected from its content (magic bytes), not from the extension or the header— is not allowed. A surface other than description or comment is also rejected. |
task_calendar_feed_not_found | not_found_error | 404 | The calendar feed (iCal) does not exist, is revoked, belongs to another company or is another user's personal feed; all cases answer the same. Only the web application emits it when rotating or revoking feeds, not the v1 API. |
task_column_capacity_exceeded | conflict_error | 409 | The board scope —the column, or the planned or archived status— has run out of the position range used to order its tasks. It is not a plan limit or a permission problem, but the technical ordering ceiling of that scope. |
task_comment_not_editable | invalid_request_error | 422 | The comment cannot be edited: only its author can change it, and comments imported or brought in by an integration are immutable to preserve what the source said. |
task_comment_not_found | not_found_error | 404 | The comment does not exist, belongs to another task or belongs to another company; all three cases answer the same. A comment is only addressable under the task it was written on. |
task_custom_field_not_found | not_found_error | 404 | The custom field does not exist, belongs to another project or belongs to another company; all three cases answer the same. Each project defines its own fields. |
task_description_too_large | invalid_request_error | 422 | The description exceeds the maximum of 100,000 characters, counted on the submitted Markdown before it is sanitised. The ceiling does not depend on the plan: it protects the editor and storage. |
task_entity_link_not_found | not_found_error | 404 | The link between the task and a document, contact, product or employee does not exist, belongs to another task or belongs to another company; all three cases answer the same. |
task_external_link_not_found | not_found_error | 404 | The external link does not exist, belongs to another task or belongs to another company. A link maintained by an integration (a forge issue or pull request) also answers this way when it is managed as if it were a manual link. |
task_label_name_in_use | conflict_error | 409 | The company already has a label with that name; the comparison is case-insensitive. Labels are shared across all the company's projects. |
task_label_not_found | not_found_error | 404 | There is no label with that identifier in the authenticated company; a label of another company answers the same. Labels belong to the company, not to a specific project. |
task_not_found | not_found_error | 404 | There is no task with that identifier or key in the authenticated company. A task of another company —or, in the employee portal, one not assigned to the caller— answers exactly the same. |
task_relation_cycle | invalid_request_error | 422 | The relation would close a cycle of subtasks or blockers: the target task already depends, directly or indirectly, on the source one, and neither could be completed first. |
task_relation_exists | conflict_error | 409 | These two tasks already have a relation of the same type, in either direction. Repeating it would add no information, so a second one is not created. |
task_relation_not_found | not_found_error | 404 | There is no relation with that identifier between tasks of the authenticated company; a relation of another company, or one already deleted, answers the same. |
task_self_relation | invalid_request_error | 422 | The source and target tasks are the same, and a task cannot be related to itself. |
task_time_entry_invoiced | invalid_request_error | 422 | The time entry is already included in an invoice. While it stays linked it cannot be edited or invoiced again, so that the invoice and the hours do not contradict each other. |
task_time_entry_not_found | not_found_error | 404 | The time entry does not exist, belongs to another task or belongs to another company; all three cases answer the same. |
task_time_not_invoiceable | invalid_request_error | 422 | The requested hours cannot be invoiced and the message names the reason: the project has no billing client or that client no longer accepts invoices, there is no hourly rate or priced product, an entry is not billable, is running or belongs to another project, there are no billable entries, or the selection is ambiguous. |
task_timer_already_running | conflict_error | 409 | You already have a running timer in this company. Each user can have at most one at a time per company, so that recorded time does not overlap between tasks. |
task_timer_not_running | invalid_request_error | 422 | A timer stop was requested, but you have no running timer in this company; it may already have been stopped from another session or device. |
task_upload_link_expired | invalid_request_error | 410 | The upload link no longer works. The subcode says why: expired, because the link timed out (it lives 30 minutes from creation), or consumed, because it was already used once and each link accepts a single submission. |
task_upload_link_not_found | not_found_error | 404 | The upload link is not valid: the token is malformed or matches no link, almost always because it was copied incompletely. An expired or already used link answers with task_upload_link_expired instead. |
Tax Reports
| Code | Type | HTTP | Description |
|---|---|---|---|
insufficient_data_for_report | invalid_request_error | 422 | The period has no data to file, or an invoice of the period lacks a mandatory field for this model — typically the customer tax id. |
invalid_period | invalid_request_error | 422 | The period does not identify a filing: the year is outside the accepted range, or the quarter is missing or out of the range 1 to 4 for a quarterly model. |
report_format_invalid | invalid_request_error | 422 | The format is outside the catalogue txt_aeat, pdf, excel. |
tax_report_not_found | not_found_error | 404 | The identifier does not resolve to any tax report of the authenticated company. |
tax_report_type_invalid | invalid_request_error | 422 | The report type is outside the catalogue modelo_303, modelo_347, modelo_130. |
unsupported_format | invalid_request_error | 422 | The requested format is not available for this model: not every filing produces every output. |
Taxes
| Code | Type | HTTP | Description |
|---|---|---|---|
duplicate_tax_default_for_document_type | invalid_request_error | 422 | Another tax of the same type is already the default for that document type, and the pair (tax type, document type) admits a single default. |
global_tax_read_only | authorization_error | 403 | The tax belongs to the Factuarea catalogue, which is read-only for companies: you can only change or delete the taxes your own company created. |
indirect_tax_regime_invalid | invalid_request_error | 422 | The indirect regime is outside the catalogue iva, igic, ipsi. |
invalid_aeat_code | invalid_request_error | 422 | The AEAT operation code is outside the closed catalogue S1, S2, S3, E1-E6, N1, N2 used by VeriFactu and SII. |
invalid_country_aeat_zone | invalid_request_error | 422 | The AEAT territorial zone is outside the catalogue peninsula, canarias, ceuta, melilla. |
invalid_country_code | invalid_request_error | 422 | The country code is not exactly two characters, so it is not a valid ISO 3166-1 alpha-2 code. |
invalid_customer_visible_label | invalid_request_error | 422 | The label shown to the customer on the document exceeds the allowed length. |
invalid_description | invalid_request_error | 422 | The description exceeds the maximum length allowed for the field. |
invalid_document_type | invalid_request_error | 422 | The document type is outside the catalogue: invoice, quote, delivery_note, proforma, purchase_invoice, recurring_invoice. |
invalid_rate_for_tax_regime | invalid_request_error | 422 | The rate does not belong to the legal grid of its regime: IGIC admits 0, 3, 5, 7, 9.5, 15 and 20%; IPSI admits 0, 0.5, 1, 2, 4, 8 and 10%. |
invalid_tax_code | invalid_request_error | 422 | The tax code is empty or longer than 50 characters. |
invalid_tax_name | invalid_request_error | 422 | The tax name is empty or longer than 255 characters. |
invalid_tax_rate | invalid_request_error | 422 | The rate falls outside the range allowed for its type: VAT 0-27%, withholding 0-47%, equivalence surcharge 0-10%, other 0-100%. |
invalid_tax_type_filter | invalid_request_error | 422 | The type filter of the by-type listing carries a value outside the enum vat, retention, surcharge, other. |
invalid_validity_window | invalid_request_error | 422 | The validity window is inverted: valid_until falls before valid_from. |
system_tax_immutable | invalid_request_error | 422 | The tax belongs to the canonical AEAT catalogue shipped with the product. Its rate, code and name are fixed so that every company shares the same fiscal reference. |
system_tax_immutable_field | invalid_request_error | 422 | The update touches a field that is frozen on a system tax; error.param names it. |
system_tax_undeletable | invalid_request_error | 422 | System taxes are part of the shared fiscal catalogue and cannot be removed: deleting one would break the documents that reference it. |
tax_applies_to_invalid | invalid_request_error | 422 | The scope of the tax is outside the catalogue sale, purchase, both. |
tax_code_already_exists | conflict_error | 409 | Another tax of the catalogue already uses that code, and codes identify taxes unambiguously. |
tax_default_axis_disabled | invalid_request_error | 422 | The tax cannot be set as the default because its category (VAT, retention or surcharge) is switched off in the company for the requested document, or in every document it would apply to when you give none. |
tax_id_required | invalid_request_error | 422 | The operation needs the tax identification number (NIF, CIF or NIE) of the party involved and the record does not carry one. |
tax_in_use | invalid_request_error | 422 | The tax is referenced by documents, products or suppliers. Removing it would leave historical documents without their fiscal reference. |
tax_inactive_cannot_be_default | invalid_request_error | 422 | A deactivated tax cannot become the default, either globally or for a document type — it would offer a hidden default that no form can pick. |
tax_not_defaultable_for_document | invalid_request_error | 422 | The tax cannot be the default of that document: it is of type other, its scope (applies_to) does not cover the document, or the document is recurring_invoice, which inherits from invoice. |
tax_not_found | not_found_error | 404 | The identifier does not match any tax of the catalogue reachable by this company. |
tax_type_invalid | invalid_request_error | 422 | The tax type is outside the catalogue vat, retention, surcharge, other. |
Time Tracking
| Code | Type | HTTP | Description |
|---|---|---|---|
clocking_outside_employment_period | invalid_request_error | 422 | The clocking instant falls before the employee's hire date or after their termination date, so nothing was written to the time record. Both the hire day and the termination day accept clockings. Approving a correction checks the current employment period again, and a rejected approval leaves the request pending. |
Transport Documents
| Code | Type | HTTP | Description |
|---|---|---|---|
delivery_note_cancelled | invalid_request_error | 422 | One of the delivery notes sent to pre-fill the transport document is cancelled, and a cancelled delivery note cannot be the source of a shipment. Nothing was created. |
invalid_cargo_measure | invalid_request_error | 422 | The declared measure of a shipment is not valid: its type is not weight or other, the weight or value is missing or not greater than zero, or the free unit is not between 1 and 30 characters. |
invalid_transport_tax_id | invalid_request_error | 422 | The tax ID of a party is not valid: a Spanish NIF, NIE or CIF with a wrong control character, or a foreign identifier outside 2 to 20 alphanumeric characters. |
invalid_vehicle_plate | invalid_request_error | 422 | A vehicle plate does not match a Spanish format (current, old provincial, trailer R, special E or historic H; Spanish plates have no vowels) nor a foreign plate of 2 to 12 alphanumeric characters with its country. |
transport_date_in_past | invalid_request_error | 422 | A transport control document must be issued before the transport starts, and one of the transport dates is earlier than today (Europe/Madrid). A draft admits any date; issuing does not. |
transport_document_cannot_be_cancelled | invalid_request_error | 422 | Only an issued transport document in progress can be cancelled; a draft is deleted instead, and a closed, cancelled or superseded one cannot be cancelled. |
transport_document_cannot_be_closed | invalid_request_error | 422 | Only an issued transport document can be closed; this one is a draft, already closed, cancelled or superseded. |
transport_document_cannot_be_deleted | invalid_request_error | 422 | Only a draft can be deleted: an issued transport document is kept as legal evidence for its whole retention period. |
transport_document_cannot_be_edited | invalid_request_error | 422 | Only a draft transport document can be edited or partially updated; this one is already issued, closed, cancelled or superseded. |
transport_document_cannot_be_modified | invalid_request_error | 422 | Only an issued transport document can be modified, and the modification must leave it with every mandatory datum and at least one shipment. |
transport_document_cannot_be_reopened | invalid_request_error | 422 | Only a manually closed transport document can be reopened, and only before its automatic-close deadline; after an automatic close it stays closed. |
transport_document_cannot_be_superseded | invalid_request_error | 422 | Only an issued transport document in progress can be marked as superseded by the carrier document. |
transport_document_file_unavailable | not_found_error | 410 | The PDF files of this transport document were purged when its retention period ended (one year after closing, cancelling or superseding it, and only because the account is closed). The document and its data are kept. |
transport_document_no_changes | invalid_request_error | 422 | The modification carries exactly the same data as the current version, so there is no new version to publish. |
transport_document_not_found | not_found_error | 404 | The identifier does not resolve to any transport control document of the authenticated company, or the public token does not exist. |
transport_document_not_issuable | invalid_request_error | 422 | The document cannot be issued: it is not a draft, or it lacks mandatory data of art. 6 of Orden FOM/2861/2012 (parties, tax IDs, shipper address, shipments with origin, destination, goods and declared measure, tractor plate or transport date). |
transport_document_not_sendable | invalid_request_error | 422 | The document cannot be emailed: it is not issued or closed, there is no recipient (no to and the carrier contact has no email), or to, cc and bcc add up to more than 5 addresses. |
transport_document_parties_immutable | invalid_request_error | 422 | After issuing, the contractual shipper and the effective carrier are fixed: the regulation does not allow changing them in a modification. |
transport_document_pdf_too_large | invalid_request_error | 422 | The PDF of the version would exceed the 5 MB (5,000,000 bytes) allowed by the regulation because of the amount of data in the document: shipments, goods lines, descriptions or notes. Nothing was saved. |
transport_document_version_limit_reached | invalid_request_error | 422 | A transport control document holds at most 50 versions and the last one is reserved for cancelling or superseding it, so it accepts no more modifications. Nothing was saved. |
transport_document_version_not_found | not_found_error | 404 | The transport document exists, but it has no version with the number requested in version: its versions go from 1 to the current one (current_version). |
transport_outside_spain | invalid_request_error | 422 | The control document only covers domestic transport, and a shipment starts or ends outside Spain. International transport is documented with the CMR consignment note. |
VeriFactu
| Code | Type | HTTP | Description |
|---|---|---|---|
alta_record_not_found | not_found_error | 404 | The invoice has no registration record, so the operation that depends on it has nothing to work with. |
anulacion_record_already_exists | conflict_error | 409 | The invoice already carries an annulment record in the chain, and annulment is reported only once. |
certificate_expired | invalid_request_error | 422 | The certificate is outside its validity window: it has expired, or it is not valid yet. |
certificate_nif_mismatch | invalid_request_error | 422 | The tax id of the certificate holder does not match the company tax id. AEAT records are signed on behalf of the company, so both must be the same. |
certificate_not_found | not_found_error | 404 | The company has no FNMT certificate matching the identifier, or none uploaded at all. |
certificate_too_large | invalid_request_error | 422 | The file exceeds the 100 KB limit, while a real FNMT certificate weighs a few kilobytes. |
chain_position_conflict | conflict_error | 409 | Two records of the same company tried to take the same position in the fingerprint chain at the same time, and the automatic retries could not resolve the collision. |
clock_drift_exceeded | invalid_request_error | 422 | The server clock drifted from NTP beyond the allowed margin. The generation timestamp is part of the AEAT fingerprint, so an unsynchronised clock would produce records AEAT rejects. |
declaracion_already_exists | conflict_error | 409 | The company already filed its SIF responsibility statement for that period. |
declaracion_not_found | not_found_error | 404 | The company has no SIF responsibility statement filed for the requested period. |
event_already_processed | invalid_request_error | 422 | That SIF event is already recorded in the event chain, and each event is processed exactly once. |
invalid_certificate_format | invalid_request_error | 422 | The file is not a PKCS#12 container: its first bytes do not match the ASN.1 structure the format requires, whatever its extension says. |
invalid_certificate_password | invalid_request_error | 422 | The password does not open the certificate file. |
invalid_representation | invalid_request_error | 422 | The representation breaks a rule: the signed Annex I or the power-of-attorney evidence is missing, the document is not a valid PDF or exceeds 5 MB, signer_name, power_of_attorney_reference or the revocation reason (reason, 3 to 500 characters) do not respect their length, valid_until is earlier than granted_on or more than 5 years after it, or the representation is already revoked (or there is no current one to revoke). |
max_retries_exceeded | invalid_request_error | 422 | It only applies to the EVENTS of the NO VERI*FACTU mode (POST /v1/companies/{company}/verifactu/events/{id}/retry): the event exhausted its transmission attempts. Billing records have NO retry limit — art. 16.4 of Order HAC/1177/2024 requires retrying at least once an hour while the incident lasts — so no record retry returns this code any more. |
mode_switch_blocked_until_year_end | invalid_request_error | 422 | VeriFactu mode was activated during this fiscal year and at least one billing record was issued. Stepping back would degrade the integrity of a chain already reported to AEAT. |
record_already_accepted | invalid_request_error | 422 | AEAT already accepted the record. Acceptance is terminal and its content is frozen as part of the fingerprint chain. |
record_immutable | invalid_request_error | 422 | The record belongs to an append-only ledger: once written, its fiscal content is closed to changes and to deletion. |
record_not_rejected | invalid_request_error | 422 | Only an alta record that AEAT accepted (or accepted with errors) or rejected can be subsanado. This record is in another state — pending remission, submitted with no answer yet or in technical error — which the retry covers, not the subsanación. |
record_not_subsanable | invalid_request_error | 422 | The record cannot be subsanado: it is not a registration (alta) record, it is not the LAST alta of its invoice (a later subsanación replaces it), the invoice is annulled, it is a rejected record whose corrected alta is already waiting to be resent, or it has no source invoice from which its data could be regenerated. |
representation_required | invalid_request_error | 422 | The remission mode asks Factuarea to submit your records to AEAT on your behalf, and the company has no current representation — neither revoked nor expired — of the kind that mode needs (the signed Annex I for social_collaborator, the registered power of attorney for power_of_attorney). |
requires_annulment | invalid_request_error | 422 | The regenerated content changes a field that takes part in the fingerprint — issuer tax id, series and number, issue date, invoice type, tax amount or total — and the chain cannot be rewritten. |
signing_certificate_unavailable | invalid_request_error | 422 | The company has VeriFactu enabled in NO VERI*FACTU mode, where every billing record is signed (Order HAC/1177/2024, arts. 6.c and 14), and there is nothing to sign it with. error.param says WHAT is missing, and it is stable: certificate = the company certificate is missing, expired or revoked, carries another company's tax id, or its .p12 file cannot be read (damaged, or the stored password is no longer valid); representation = in the third-party remission modes, the representation that lets Factuarea sign on the company's behalf is not active; system_certificate = the Factuarea certificate is unavailable or cannot be read. Without a signature there is no valid record, and an issued or annulled invoice cannot be left without its own, so the operation is rejected before it runs. |
sii_excluded | invalid_request_error | 422 | The company is registered with SII, and SII filers are excluded from the VeriFactu regulation. |
social_collaborator_unavailable | invalid_request_error | 422 | The social collaboration agreement with AEAT is not yet in force on this instance, so the social_collaborator mode cannot be selected. |
system_certificate_unavailable | api_error | 500 | The Factuarea certificate that submits records in the third-party modes is missing, expired or revoked. It is a problem on our side, not in your request. |
verifactu_already_submitted | invalid_request_error | 422 | The invoice already has its registration record. Exactly one registration exists per invoice, so a second one would break the idempotency of the chain. |
verifactu_mode_invalid | invalid_request_error | 422 | The mode is outside the catalogue verifactu / no_verifactu. |
verifactu_not_eligible | invalid_request_error | 422 | The invoice cannot be registered with AEAT right now: the company is not on VeriFactu mode, it has no active certificate, or the certificate is revoked or issued for a different tax id. When issuing or annulling, the same code with the subcode signing_certificate_unavailable means the company, with VeriFactu enabled in NO VERI*FACTU mode, has nothing to sign the record with (error.param: certificate, representation or system_certificate, depending on what is missing), and with other error.param values that a field of the invoice does not fit the alta record (read error.param and error.message). |
verifactu_record_not_found | not_found_error | 404 | The identifier does not match any billing record of the authenticated company. |
verifactu_transmission_failed | invalid_request_error | 422 | The transmission of the record to AEAT did not complete: the endpoint was unreachable or answered with an incident. |
Webhooks
| Code | Type | HTTP | Description |
|---|---|---|---|
account_webhook_endpoint_limit_reached | invalid_request_error | 422 | The account reached the number of account webhook endpoints its tier allows in that environment. The cap is counted per account and per environment (live or test) and includes disabled endpoints: only deleting an endpoint frees a slot. |
addon_required | payment_required_error | 402 | Creating webhook endpoints requires a plan that includes them: for company endpoints, the Developer API add-on of the company; for account endpoints, the plan of the payer of the account. That subscription is missing here — the free tier allows zero endpoints. |
api_version_invalid_format | invalid_request_error | 422 | The payload version of the endpoint is not a YYYY-MM-DD date. |
api_version_unsupported | invalid_request_error | 422 | The payload version is well formed but is not among the ones the platform serves. |
custom_header_blocklisted | invalid_request_error | 422 | One of the custom headers is reserved: the HTTP layer manages it (host, content-type, content-length, user-agent), Factuarea sends it as part of the signed contract (factuarea-*), or the proxy owns it (x-forwarded-*). |
custom_header_value_too_long | invalid_request_error | 422 | The value of a custom header exceeds 1024 characters. |
invalid_url_target | invalid_request_error | 422 | The destination host is not a publicly reachable address, so we refuse to deliver to it: private ranges (RFC 1918), loopback, link-local, CGNAT (100.64.0.0/10), IPv6 ULA (fc00::/7) and multicast are all rejected. Despite the wording of the message, the restriction applies in every environment, not only in production. |
replay_delivery_not_retryable | invalid_request_error | 422 | Only failed deliveries can be replayed. A delivery that succeeded, or one still in flight, has nothing to resend. |
replay_event_expired | invalid_request_error | 422 | The event behind the delivery was purged by the 30-day retention policy, so there is no payload left to resend. |
timeout_seconds_out_of_range | invalid_request_error | 422 | timeout_seconds falls outside the range 1 to 30 seconds. |
too_many_custom_headers | invalid_request_error | 422 | The endpoint declares more than 20 custom headers. |
webhook_delivery_not_found | not_found_error | 404 | The identifier does not match any delivery attempt, or the delivery falls outside the retention window kept for the history. |
webhook_endpoint_degraded | invalid_request_error | 422 | The endpoint is degraded after repeated delivery failures, so test pings are refused while it stays in that state. |
webhook_endpoint_not_found | not_found_error | 404 | The identifier does not resolve to any webhook endpoint of the authenticated company. |
webhook_secret_recently_rotated | invalid_request_error | 422 | The signing secret was rotated less than five minutes ago. The grace window lets your receiver accept both secrets during the switch; rotating again inside it would invalidate signatures still in flight. It answers as a 422 business_rule_violation with error.subcode webhook_secret_recently_rotated; it is not a request limit and consumes no rate-limit bucket. |